为类添加一个decorate函数

Rug*_*rra 6 python class decorator descriptor

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

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...
Run Code Online (Sandbox Code Playgroud)

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

ROOT.TChain.DrawPlot = _DrawPlot
Run Code Online (Sandbox Code Playgroud)

当我称这种方法时:

chain = TChain()
chain.DrawPlot(opts)
Run Code Online (Sandbox Code Playgroud)

我有:

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

为什么不传播自我?

Mik*_*ham 3

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

\n\n

如果您不熟悉描述符,请在http://docs.python.org/reference/datamodel.html#descriptors上进行一些解释。、和方法改变了作为属性与对象交互的方式__get____set____delete__

\n\n
\n\n

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

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

或者按照以下方式修改你的课程

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

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

\n