我正在编写一个收集和显示科学仪器数据的应用程序。其中一个数据是频谱:基本上只是一个值列表,加上一个带有一些元数据的字典。一旦应用程序收集了数据,它就不会改变,因此列表和元数据都可以被认为是不可变的。
我想通过大量记忆在频谱上执行计算的函数来利用这个优势。这是一个玩具示例:
class Spectrum(object):
def __init__(self, values, metadata):
self.values = values
self.metadata = metadata
# self.values and self.metadata should not change after this point.
@property
def first_value(self):
return self.values[0]
def multiply_by_constant(self, c):
return [c*x for x in self.values]
def double(self):
return self.multiply_by_constant(2)
我想要的是默认情况下要记住这些方法中的每一种。有没有办法(一个元类?)来实现这一目标,而无需复制one of these memoization decorators并在任何地方写@memoize
?
答案 0 :(得分:1)
我继续写了一个元类来解决你的问题。它遍历所有属性并检查它们是否可调用(通常是函数,方法或类)并装饰它们。当然,您可以将decorator
设置为您的memoizing装饰器(例如functools.lru_cache
)。
如果仅想要修饰方法,而不是任何可调用方法,则可以将测试hasattr(val, "__call__")
替换为inspect.ismethod(val)
。但它可能会在将来引入一个错误,你不记得它只适用于方法,并添加一个不会被记忆的函数或类!
有关Python中元类的更多信息,请参阅this SO问题。
def decorate(f):
def wrap(*args, **kwargs):
# Print a greeting every time decorated function is called
print "Hi from wrap!"
return f(*args, **kwargs)
return wrap
class DecorateMeta(type):
def __new__(cls, name, bases, dct):
# Find which decorator to use through the decorator attribute
try:
decorator = dct["decorator"]
except KeyError:
raise TypeError("Must supply a decorator")
# Loop over all attributes
for key, val in dct.items():
# If attribute is callable and is not the decorator being used
if hasattr(val, "__call__") and val is not decorator:
dct[key] = decorator(val)
return type.__new__(cls, name, bases, dct)
class Test:
__metaclass__ = DecorateMeta
decorator = decorate
def seasonal_greeting(self):
print "Happy new year!"
Test().seasonal_greeting()
# Hi from wrap!
# Happy new year!
答案 1 :(得分:1)
我将冰箱的答案改编成了这个:
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)
return type.__new__(cls, name, bases, dct)
装饰器是提前知道的,所以我不需要在对象本身中指定它。我也只关心方法 - 虽然由于我还不了解的原因,当Immutable.__new__
看到它们时所有对象的方法都是未绑定的,因此它们是函数,而不是方法。我还排除了名称以下划线开头的方法:在记忆的情况下,您不想对__init__
或__eq__
等方法做任何事情。