根据this previous question关于默认情况下记忆所有类方法的回答,我正在使用这个元类:
from inspect import isfunction
class Immutable(type):
def __new__(cls, name, bases, dct):
for key, val in dct.items():
# Look only at methods/functions; ignore those with
# "special" names (starting with an underscore)
if isfunction(val) and val.__name__[0] != '_':
dct[key] = memoized(val)
elif hasattr(val, 'fget'):
# It's a property; we currently can't memoize these
pass
return type.__new__(cls, name, bases, dct)
此元类具有将装饰器memoized
应用于类中的所有函数和方法的效果。唯一的问题是它不适用于属性。 (使用这个元类的类被视为不可变类,所以我只担心这里的readonly属性。)如果我尝试做类似的事情
from time import sleep
class Foo(object):
__metaclass__ = Immutable
@property
def slow_calculation(self):
sleep(5) # simulate an intensive calculation
return 4
然后slow_calculation
没有被记忆 - 每次被叫时都会有5秒的延迟,而不仅仅是第一次。
问题是property()
返回property
个对象,而不是函数,因此元类的isfunction
中的__new__
测试不会捕获属性。如您所见,我添加了一个查找属性的测试,但后来我无法弄清楚如何将memoized
装饰器应用于属性getter fget
。我想也许我可以说
elif hasattr(val, 'fget'):
val.fget = memoized(val.fget)
dct[key] = val
但在这种情况下我得到了
Traceback (most recent call last):
[...]
File "utils.py", line 54, in __new__
val.fget = memoized(val.fget)
TypeError: Error when calling the metaclass bases
readonly attribute
是否有其他方法将装饰器应用于属性getter?
答案 0 :(得分:2)
prop = property(memoized(prop.fget), prop.fset, prop.fdel, prop.__doc__)
不要修改属性;做一个新的。