python中的类Decorator装饰方法

发布于 2024-12-27 07:00:37 字数 1104 浏览 3 评论 0原文

我试图使用装饰器来记忆,装饰器是一个类而不是一个函数,但我收到错误,

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()

I'm trying to memoize using a decorator with the decorator being a class not a function, but I'm getting the error

TypeError: seqLength() takes exactly 2 arguments (1 given)

I'm guessing this has something to do with the classes, but not sure what's wrong from there.

The code:

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()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

脱离于你 2025-01-03 07:00:37

从语法上讲,这很令人困惑。目前尚不清楚 self.func 是您的 memoize 的一部分还是作为其他类的其他对象的一部分的单独函数。 (顺便说一句,你的意思是后者)

        value = self.func(self, *args)

这样做是为了明确 the_func 只是一个函数,而不是 memoize 类的成员。

        the_func= self.func
        value= the_func( *args )

这种事情可以防止对 self. 所绑定的类产生混淆。

另外,请拼写它Memoize。以大写字母开头。毕竟,这是一个类定义。

This is confusing, syntactically. It's not clear if self.func is part of your memoize or a separate function that's part of some other object of some other class. (You mean the latter, BTW)

        value = self.func(self, *args)

Do this to make it clear that the_func is just a function, not a member of the memoize class.

        the_func= self.func
        value= the_func( *args )

That kind of thing prevents confusion over the class to which self. is bound.

Also, please spell it Memoize. With a leading capital letter. It is a class definition, after all.

绾颜 2025-01-03 07:00:37

使用类作为装饰器很棘手,因为您必须实现描述符协议< /a> 正确(当前接受的答案没有。)一个非常非常简单的解决方案是使用包装函数,因为它们会自动正确地实现描述符协议。与您的类等效的包装器将是:

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

Using a class as a decorator is tricky, because you have to implement the descriptor protocol correctly (the currently accepted answer doesn't.) A much, much easier solution is to use a wrapper function, because they automatically implement the descriptor protocol correctly. The wrapper equivalent of your class would be:

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

When have so much state you want to encapsulate it in a class anyway, you can still use a wrapper function, for example like so:

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
笑饮青盏花 2025-01-03 07:00:37

装饰器只是 foo =decorator(foo) 的语法糖,因此在这种情况下,您最终会将 seqLengthself 设为memoize 而不是 collat​​z。您需要使用描述符。此代码对我有用:

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

A decorator is just syntactic sugar for foo = decorator(foo), so in this case you're ending up making the self of seqLength be memoize instead of collatz. You need to use descriptors. This code works for me:

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]

More on descriptors:

http://docs.python.org/howto/descriptor.html#descriptor-example

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文