我正在尝试使用可以接受参数的缓存属性装饰器。
我查看了这个实现:http://www.daniweb.com/software-development/python/code/217241/a-cached-property-decorator
from functools import update_wrapper
def cachedProperty (func ,name =None ):
if name is None :
name =func .__name__
def _get (self ):
try :
return self .__dict__ [name ]
except KeyError :
value =func (self )
self .__dict__ [name ]=value
return value
update_wrapper (_get ,func )
def _del (self ):
self .__dict__ .pop (name ,None )
return property (_get ,None ,_del )
但我遇到的问题是,如果我想使用参数,我不能用@语法调用装饰器:
@cachedProperty(name='test') # This does NOT work
def my_func(self):
return 'ok'
# Only this way works
cachedProperty(my_func, name='test')
如何使用带有装饰器参数的@语法?
谢谢
最佳答案
您需要一个装饰器工厂,这是另一个生产装饰器的包装器:
from functools import wraps
def cachedProperty(name=None):
def decorator(func):
if decorator.name is None:
decorator.name = func.__name__
@wraps(func)
def _get(self):
try:
return self.__dict__[decorator.name]
except KeyError:
value = func(self)
self.__dict__[decorator.name] = value
return value
def _del(self):
self.__dict__.pop(decorator.name, None)
return property(_get, None, _del)
decorator.name = name
return decorator
将其用作:
@cachedProperty(name='test')
def my_func(self):
return 'ok'
装饰器实际上只是语法糖:
def my_func(self):
return 'ok'
my_func = cachedProperty(name='test')(my_func)
所以只要 @
之后的表达式返回你的装饰器 [*] 表达式本身实际上做了什么并不重要。
在上面的例子中,@cachedProperty(name='test')
部分首先执行了cachedProperty(name='test')
,然后返回值call 用作装饰器。在上面的例子中,返回了decorator
,所以my_func
函数是通过调用decorator(my_func)
来装饰的,调用的返回值是 property
对象,所以它将替换 my_func
。
[*] @
表达式语法被有意限制在允许的范围内。您可以执行属性查找和调用,仅此而已,decorator
grammar rule只允许在带点的名称末尾使用参数进行可选调用(其中点是可选的):
decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE)
这是一个 deliberate limitation的语法。
关于带有@语法的python装饰器参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22271923/