Python:从子类调用超类方法时超过最大递归深度
我有一个由三个类组成的继承链:Baz继承自Bar继承自Foo。我想在Foo类中定义一个方法,当在子类中调用该方法时,该方法返回其父类的输出,并附加其自身的内容。这是所需的输出: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
>>> 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