[英]Decorator to invoke instance method
我有一個方法為do_something(self,a,b,c)
的類A
,另一個實例方法是對輸入進行驗證並檢查權限的實例方法can_do_something(self,a,b,c)
。
這是我代碼中的常見模式,我想編寫一個接受驗證函數名稱並執行測試的裝飾器。
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
調用功能如下
@validate_input('can_do_something')
def do_something(self,a,b,c):
return a + b + c
問題是我不確定如何通過驗證功能來保持self
。 我已經將驗證fn名稱與getattr
因此可以在實例的上下文中運行fn,但是我不能對func(*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
更優雅,它還支持靜態方法。
向@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
但是,當我嘗試在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)
我得到以下內容:
NameError: name 'Dummy' is not defined
那么,關於這個問題,Django模型和Object之間有什么區別?
我認為這可以滿足您的需求:
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('')
輸出為:
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
更新的答案
由於validate_input
裝飾器將Dummy
作為參數時,尚未定義Dummy
類,因此發生錯誤( NameError: name 'Dummy' is not defined
)。 我想這可能會以不同的方式實現,但是現在這就是Python的工作方式。 我看到的最簡單的解決方案是堅持使用getattr
,因為它可以在運行時查找方法,所以該方法可以工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.