类装饰器在python中的装饰方法

时间:2012-01-13 19:31:51

标签: python decorator memoization

我正在尝试使用装饰器进行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()

3 个答案:

答案 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

相关问题