我正在尝试使用装饰器进行memoize,装饰器是一个类而不是一个函数,但我收到了错误
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()
答案 0 :(得分:2)
这在语法上令人困惑。目前尚不清楚self.func
是否是你的memoize的一部分,还是一个单独的函数,它是某个其他类的其他对象的一部分。 (你的意思是后者,BTW)
value = self.func(self, *args)
这样做是为了明确the_func
只是一个函数,而不是memoize类的成员。
the_func= self.func
value= the_func( *args )
这种事情可以防止对self.
绑定的类产生混淆。
另外,请拼写Memoize
。带着领先的大写字母。毕竟,这是一个类定义。
答案 1 :(得分:2)
使用类作为装饰器是很棘手的,因为你必须正确实现the descriptor protocol(当前接受的答案不是。)一个更容易的解决方案是使用包装函数,因为它们会自动实现描述符协议正确。你的类的包装器等价物是:
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 :(得分:-1)
装饰器只是foo = decorator(foo)
的语法糖,所以在这种情况下,你最终会使self
的{{1}}成为seqLength
而不是memoize
}。你需要使用描述符。这段代码适合我:
collatz
有关描述符的更多信息:
http://docs.python.org/howto/descriptor.html#descriptor-example