[英]Decorator to invoke instance method
I have a class A
with method do_something(self,a,b,c)
and another instance method that validates the input and check permissions named can_do_something(self,a,b,c)
. 我有一个方法为do_something(self,a,b,c)
的类A
,另一个实例方法是对输入进行验证并检查权限的实例方法can_do_something(self,a,b,c)
。
This is a common pattern in my code and I want to write a decorator that accepts a validation function name and perform the test. 这是我代码中的常见模式,我想编写一个接受验证函数名称并执行测试的装饰器。
def validate_input(validation_fn_name):
def validation_decorator(func):
def validate_input_action(self,*args):
error = getattr(self,validation_fn_name)(*args)
if not error == True:
raise error
else:
return func(*args)
return validate_input_action
return validation_decorator
Invoking the functions as follows 调用功能如下
@validate_input('can_do_something')
def do_something(self,a,b,c):
return a + b + c
Problem is that i'm not sure how to maintain self
through out the validation function. 问题是我不确定如何通过验证功能来保持self
。 I've used the validation fn name with getattr
so the fn could be ran in the context of the instance but i cannot do that for func(*args)
. 我已经将验证fn名称与getattr
因此可以在实例的上下文中运行fn,但是我不能对func(*args)
这样做。
So what is the proper way to achieve this ? 那么实现这一目标的正确方法是什么?
Thanks. 谢谢。
EDIT 编辑
So following @André Laszlo answer I realized that self is just the first argument so there is no need to use getattr
at all but just pass on the *args
. 因此,在@AndréLaszlo回答之后,我意识到self只是第一个参数,因此根本不需要使用getattr
,而只需传递*args
。
def validate_input(validation_fn):
def validation_decorator(func):
def validate_input_action(*args):
error = validation_fn(*args)
if not error == True:
raise error
else:
return func(*args)
return validate_input_action
return validation_decorator
Much more elegant and it also supports static methods as well. 更优雅,它还支持静态方法。
Adding a static method to @André Laszlo example proves the decorator is working : 向@AndréLaszlo示例添加静态方法证明装饰器正在工作:
class Foo(object):
@staticmethod
def validate_baz(a,b,c):
if a > b:
return ValueError('a gt b')
@staticmethod
@validate_input(Foo.validate_baz)
def baz(a,b,c):
print a,b,c
>>> Foo.baz(1,2,3)
1 2 3
>>> Foo.baz(2,1,3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in validate_input_action
ValueError: a gt b
But, when i'm trying to do them same thing in a django model: 但是,当我尝试在Django模型中做相同的事情时:
from django.db import models
from django.conf import settings
settings.configure()
class Dummy(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=10)
def can_say_name(self):
if name is None:
return Exception('Does not have a name')
@validate_input(can_say_name)
def say_name(self):
print self.name
@staticmethod
def can_create_dummy(name):
if name == 'noname':
return Exception('No name is not a name !')
@staticmethod
@validate_input(Dummy.can_create_dummy)
def create_dummy(name):
return Dummy.objects.create(name=name)
I get the following : 我得到以下内容:
NameError: name 'Dummy' is not defined
So what is the different between a django model and an Object in relation to this issue ? 那么,关于这个问题,Django模型和Object之间有什么区别?
I think this does what you want: 我认为这可以满足您的需求:
def validate_input(validation_fn_name):
def validation_decorator(func):
def validate_input_action(self, *args):
error = getattr(self, validation_fn_name)(*args)
if error is not None:
raise error
else:
arglist = [self] + list(args)
return func(*arglist)
return validate_input_action
return validation_decorator
class Foo(object):
def validate_length(self, arg1):
if len(arg1) < 3:
return ValueError('%r is too short' % arg1)
@validate_input('validate_length')
def bar(self, arg1):
print "Arg1 is %r" % arg1
if __name__ == "__main__":
f = Foo()
f.bar('hello')
f.bar('')
Output is: 输出为:
Arg1 is 'hello'
Traceback (most recent call last):
File "validator.py", line 27, in <module>
f.bar('')
File "validator.py", line 6, in validate_input_action
raise error
ValueError: '' is too short
Updated answer 更新的答案
The error ( NameError: name 'Dummy' is not defined
) occurs because the Dummy
class is not defined yet when the validate_input
decorator gets Dummy
as an argument. 由于validate_input
装饰器将Dummy
作为参数时,尚未定义Dummy
类,因此发生错误( NameError: name 'Dummy' is not defined
)。 I guess this could have been implemented differently, but for now that's the way Python works. 我想这可能会以不同的方式实现,但是现在这就是Python的工作方式。 The easiest solution that I see is to stick to using getattr
, which will work because it looks up the method at run time. 我看到的最简单的解决方案是坚持使用getattr
,因为它可以在运行时查找方法,所以该方法可以工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.