Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:从子类调用超类方法时超过最大递归深度_Python_Exception_Inheritance_Recursion - Fatal编程技术网

Python:从子类调用超类方法时超过最大递归深度

Python:从子类调用超类方法时超过最大递归深度,python,exception,inheritance,recursion,Python,Exception,Inheritance,Recursion,我有一个由三个类组成的继承链:Baz继承自Bar继承自Foo。我想在Foo类中定义一个方法,当在子类中调用该方法时,该方法返回其父类的输出,并附加其自身的内容。这是所需的输出: >>> foo = Foo() >>> bar = Bar() >>> baz = Baz() >>> print foo.get_defining_fields() ['in Foo'] >>> print bar.get_def

我有一个由三个类组成的继承链:Baz继承自Bar继承自Foo。我想在Foo类中定义一个方法,当在子类中调用该方法时,该方法返回其父类的输出,并附加其自身的内容。这是所需的输出:

>>> foo = Foo()
>>> bar = Bar()
>>> baz = Baz()
>>> print foo.get_defining_fields()
['in Foo']
>>> print bar.get_defining_fields()
['in Foo', 'in Bar']
>>> print baz.get_defining_fields()
['in Foo', 'in Bar', 'in Baz']
问题是,我误解了在子类调用的超类方法中使用
super()
,或者其他一些子类细节。这个钻头工作正常:

>>> print foo.get_defining_fields()
['in Foo']
但是
bar.get\u defining\u fields()
会产生一个无限循环,它自己运行直到引发
RuntimeError
而不是调用
foo.get\u defining\u fields
并像我希望的那样停在那里

这是密码

class Foo(object):
    def _defining_fields(self):
        return ['in Foo']

    def get_defining_fields(self):
        if self.__class__ == Foo:
            # Top of the chain, don't call super()
            return self._defining_fields()
        return super(self.__class__, self).get_defining_fields() + self._defining_fields()

class Bar(Foo):
    def _defining_fields(self):
        return ['in Bar']

class Baz(Bar):
    def _defining_fields(self):
        return ['in Baz']
因此,在超类中定义了
get\u defining\u字段
,其中的
super()
调用使用
self.\uu class\uuuuu
试图将正确的子类名称传递给每个子类中的调用。在Bar中调用时,它解析为
super(Bar,self).get\u-defining\u-fields()
,这样
foo.get\u-defining\u-fields()
返回的列表将前置到
far.get\u-defining\u-fields()
返回的列表

如果您正确理解Python的继承机制和
super()
的内部工作原理,这可能是一个简单的错误,但由于我显然不了解,如果有人能为我指出正确的方法,我将不胜感激


EDIT:根据Daniel Roseman的回答,我尝试用以下表单替换
super()
调用:
return super(Foo,self)。get\u defining\u fields()+self.\u defining\u fields()

现在,无限递归不再发生,但在调用
bar.get\u defining\u fields()
时,我遇到了一个不同的错误:

还有别的地方不对劲


编辑:是的,终于找到了我在这里遗漏的东西。将Daniel的更新答案标记为已接受答案。

问题在于:

 return super(self.__class__, self)...
self.\uuuuu类\uuuuu
始终指当前的具体类。所以在Bar中,它指的是Bar,在Baz中,它指的是Baz。因此,Bar调用了超类的方法,但是
self.\uuuuu类\uuuuu
仍然引用Bar,而不是Foo。所以你会得到一个无休止的递归

这就是为什么你必须在super中特别提到这个类。像这样:

return super(Foo, self)...
编辑正确,因为只有顶级类定义
get\u defining\u字段

你走错了路,真的。这根本不是
super
的工作。我认为通过迭代
self.\uuuuu class.\uuuuu mro.\uuuu
可以获得更好的结果,这是访问超类的方法解析顺序的方法:

class Foo(object):
    def _defining_fields(self):
        return ['in Foo']

    def get_defining_fields(self):
        fields = []
        for cls in self.__class__.__mro__:
            if hasattr(cls, '_defining_fields'):
                fields.append(cls._defining_fields(self))
        return fields

Charles Beattie:Python 3也是如此,所有类都是新样式的类,但在Python 2中不受鼓励。我删除了我的评论,但之前我问他为什么从object派生。因此jena回答说,这解决了递归问题,但却带来了AttributeError。我相应地编辑了这个问题。是的,我的想法是混乱的,我的印象是Bar将继承get_定义_字段,从Bar下运行它将使其成为
super()
调用中的“Bar方法”。
class Foo(object):
    def _defining_fields(self):
        return ['in Foo']

    def get_defining_fields(self):
        fields = []
        for cls in self.__class__.__mro__:
            if hasattr(cls, '_defining_fields'):
                fields.append(cls._defining_fields(self))
        return fields