6

我有一个装饰功能(简化版):

class Memoize:
    def __init__(self, function):
        self.function = function
        self.memoized = {}
    def __call__(self, *args, **kwds):
        hash = args
        try:
            return self.memoized[hash]
        except KeyError:
            self.memoized[hash] = self.function(*args)
            return self.memoized[hash]


@Memoize
def _DrawPlot(self, options):
    do something...

现在我想将此方法添加到预先存在的类中。

ROOT.TChain.DrawPlot = _DrawPlot

当我调用这个方法时:

chain = TChain()
chain.DrawPlot(opts)

我有:

self.memoized[hash] = self.function(*args)
TypeError: _DrawPlot() takes exactly 2 arguments (1 given)

为什么它不传播自我?

4

1 回答 1

3

问题是您已经定义了自己的可调用类,然后尝试将其用作方法。当您将函数用作属性时,将函数作为属性访问时会调用它的__get__方法来返回函数本身以外的东西——绑定方法。当您拥有自己的类而没有定义__get__时,它只会返回您的实例而不会隐式传递self

如果您不熟悉描述符,请参阅 http://docs.python.org/reference/datamodel.html#descriptors 。__get__和方法改变了作为属性与对象交互的方式__set____delete__


您可以实现为函数并使用函数已有memoize的内置魔法__get__

import functools

def memoize(f):
    @functools.wraps(f)
    def memoized(*args, _cache={}): 
        # This abuses the normally-unwanted behaviour of mutable default arguments.
        if args not in _cache:
            _cache[args] = f(*args)
        return _cache[args]
    return memoized

或者通过修改你的类

import functools

class Memoize(object): #inherit object
    def __init__(self, function):
        self.function = function
        self.memoized = {}
    def __call__(self, *args): #don't accept kwargs you don't want.
        # I removed "hash = args" because it shadowed a builtin function and 
        # because it was untrue--it wasn't a hash, it was something you intended for
        # Python to hash for you.
        try:
            return self.memoized[args]
        except KeyError:
            self.memoized[args] = self.function(*args)
            return self.memoized[args]
    def __get__(self, obj, type):
        if obj is None: #We looked up on the class
            return self

        return functools.partial(self, obj)

请注意,如果您传入的任何参数是可变的(好吧,从技术上讲,不可散列),这两个都会阻塞。这可能适合您的情况,但您可能还想处理args不可散列的情况。

于 2010-03-23T16:26:42.660 回答