在Python中为方法装饰的类装饰器
我正在尝试使用一个装饰器来实现记忆化,而这个装饰器是一个类而不是一个函数,但我遇到了错误。
TypeError: seqLength() takes exactly 2 arguments (1 given)
我猜这可能和类有关,但我不太确定具体哪里出错了。
代码如下:
import sys
class memoize(object):
'''memoize decorator'''
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
try:
return self.cache[args]
except KeyError:
value = self.func(self, *args)
self.cache[args] = value
return value
class collatz(object):
def __init__(self, n):
self.max = 1
self.n = n
@memoize
def seqLength(self, n):
if n>1:
if n%2 == 0:
return 1+self.seqLength(n/2)
else:
return 1+self.seqLength(3*n+1)
else:
return 1
def maxLength(self):
for n in xrange(1, self.n):
l = self.seqLength(n)
if l > self.max:
self.max = n
return self.max
n = int(sys.argv[1])
c = collatz(n)
print c.maxLength()
3 个回答
2
把一个类当作装饰器来用其实挺复杂的,因为你需要正确实现描述符协议(而目前的答案并没有做到这一点)。其实有一个简单得多的解决办法,就是使用一个包装函数,因为包装函数会自动正确实现描述符协议。你类的包装函数版本可以这样写:
import functools
def memoize(func):
cache = {}
@functools.wraps(func)
def wrapper(*args):
try:
return cache[args]
except KeyError:
value = func(*args)
cache[args] = value
return value
return wrapper
如果你有很多状态想要封装在一个类里,其实你仍然可以使用包装函数,比如这样:
import functools
class _Memoize(object):
'''memoize decorator helper class'''
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
try:
return self.cache[args]
except KeyError:
value = self.func(*args)
self.cache[args] = value
return value
def memoize(func):
o = _Memoize(func)
@functools.wraps(func)
def wrapper(*args):
return o(*args)
return wrapper
2
这段话有点让人困惑,从语法上看不太清楚 self.func
是你自己定义的记忆化函数的一部分,还是属于其他类的某个对象的一个单独函数。(顺便说一下,你是指后者)
value = self.func(self, *args)
这样做可以让人更清楚 the_func
只是一个普通的函数,而不是记忆化类的成员。
the_func= self.func
value= the_func( *args )
这样可以避免对 self.
绑定的类产生混淆。
另外,请记得把它写成 Memoize
,首字母要大写。毕竟这是一个类的定义。
-1
装饰器其实就是一种语法上的简化,像这样写:foo = decorator(foo)
。在这个例子中,你会发现seqLength
的self
变成了memoize
,而不是collatz
。你需要使用描述符。下面这段代码对我来说是有效的:
class memoize(object):
'''memoize descriptor'''
def __init__(self, func):
self.func = func
def __get__(self, obj, type=None):
return self.memoize_inst(obj, self.func)
class memoize_inst(object):
def __init__(self, inst, fget):
self.inst = inst
self.fget = fget
self.cache = {}
def __call__(self, *args):
# if cache hit, done
if args in self.cache:
return self.cache[args]
# otherwise populate cache and return
self.cache[args] = self.fget(self.inst, *args)
return self.cache[args]
关于描述符的更多信息:
http://docs.python.org/howto/descriptor.html#descriptor-example