Python 类装饰器和最大递归深度超出

4 投票
2 回答
2246 浏览
提问于 2025-04-15 23:44

我在尝试定义一个类装饰器的时候,遇到了一个问题。这个问题出现在被装饰的类的 __init__ 方法里。如果在这个 __init__ 方法中调用了 super,就会出现一个错误,提示 最大递归深度超出

代码示例:

def decorate(cls):
    class NewClass(cls): pass
    return NewClass

@decorate
class Foo(object):
    def __init__(self, *args, **kwargs):
        super(Foo, self).__init__(*args, **kwargs)

我哪里做错了呢?

谢谢,Michał

编辑 1

感谢 Mike Boers 的回答,我意识到我真正想问的是,应该怎么做才能让 super(Foo, self) 指向正确的类。

我还有两个限制条件。我想调用 Foo.__init__ 方法,而且我不能改变 Foo 类的定义。

编辑 2

我已经解决了这个问题。我修改了装饰器函数的内容。我没有返回一个新类,而是直接包装了原始类的方法。

2 个回答

5

记住,装饰器其实就是一种语法上的简化,方便我们使用:

>>> Foo = decorate(Foo)

在这个例子中,Foo这个名字实际上指的是NewClass这个类。在Foo.__init__这个方法里,你实际上是在调用NewClass的父类__init__方法,而这个父类__init__就是Foo.__init__(也就是现在正在执行的那个)。

因此,你的Foo.__init__方法一直在调用它自己的__init__,这就导致了无限递归,也就是一直在重复调用自己。

5

你需要重写 NewClass.__init__ 方法,以防止递归,因为 NewClass.__init__ 实际上是 Foo.__init__,它会一直调用自己。

def decorate(cls):
    class NewClass(cls):
        def __init__(self):
            pass
    return NewClass

新想法:

不如不去继承它?也许可以试试猴子补丁?

def decorate(cls):
    old_do_something = cls.do_something
    def new_do_something(self):
        print "decorated",
        old_do_something(self)

    cls.do_something = new_do_something
    return cls

@decorate
class Foo(object):
    def __init__(self, *args, **kwargs):
        super(Foo, self).__init__(*args, **kwargs)

    def do_something(self):
        print "Foo"

f = Foo()
f.do_something()

撰写回答