我有一个装饰功能(简化版):
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)
为什么不传播自我?
答案 0 :(得分: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
不可用的情况。