Python类装饰器和最大递归深度超过限制

4
我尝试定义一个类装饰器。我在被装饰的类中遇到了一个问题,即如果该类的__init__方法调用了super方法,则会引发RuntimeError maximum recursion depth exceeded错误。
代码示例:
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

我已经解决了这个问题。我修改了装饰器函数体。我不返回新类,而是包装原始类的方法。


可能是[类装饰器,继承,super()和最大递归深度]的重复问题。(https://dev59.com/gkzSa4cB1Zd3GeqPqeAI) - Jochen Ritzel
你如何能够将装饰器应用于Foo类,但又不能更改它的定义? - Mike Boers
我正在编写一个使用Ajax验证的Django应用程序。它应该是通用的,不需要更改表单类定义。 - Michał Lula
2个回答

5

请记住,装饰器只是一种语法糖,其实质为:

>>> Foo = decorate(Foo)

在这种情况下,“Foo”实际上是指“NewClass”类。在“Foo.__init__”方法中,您实际上要求调用“NewClass”的超级“__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

新想法:
不要去继承它,而是采用 monkey patching(猴子补丁)的方式,这可能会更好。
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()

好的,但我想执行Foo.__init__方法。我也不能编辑Foo类定义。 - Michał Lula
1
希望“不要子类化”是一个单独的答案,这样我就可以在修改实际类(在太多情况下都不起作用)之前+1它。 - claytond

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接