【问题标题】:Memoizing all methods by default默认记住所有方法
【发布时间】:2013-12-26 21:05:06
【问题描述】:

我正在编写一个应用程序来收集和显示来自科学仪器的数据。其中一个数据是频谱:本质上只是一个值列表,加上一个带有一些元数据的字典。一旦应用程序收集了数据,它就不会改变,因此列表和元数据都可以被认为是不可变的。

我想通过大量记忆在频谱上执行计算的函数来利用这一点。这是一个玩具示例:

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 的情况下完成此任务?

【问题讨论】:

标签: python immutability


【解决方案1】:

我继续编写了一个元类来解决您的问题。它遍历所有属性并检查它们是否可调用(通常是函数、方法或类)并装饰那些可调用的。当然,您可以将decorator 设置为您的记忆装饰器(例如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!

【讨论】:

    【解决方案2】:

    我将冰箱的答案改编成这样:

    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__之类的方法做任何事情。

    【讨论】:

      猜你喜欢
      • 2011-11-14
      • 2014-01-11
      • 2015-04-27
      • 2013-01-23
      • 2015-03-31
      • 1970-01-01
      • 1970-01-01
      • 2011-03-18
      • 2023-03-28
      相关资源
      最近更新 更多