我有一个包含三个类的继承链: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 class)方法中使用 super() 或其他一些子类化细节有一些误解。这个位工作正常:
>>> print foo.get_defining_fields()
['in Foo']
但是 bar.get_defining_fields() 会产生一个无限循环,它会自行运行直到出现 RuntimeError 而不是调用 foo.get_defining_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_defining_fields 在父类(super class)中定义,其中的 super() 调用使用 self.__class__ 试图通过在每个子类中调用正确的子类名称。在 Bar 中调用时,它解析为 super(Bar, self).get_defining_fields() 以便 foo.get_defining_fields() 返回的列表将被添加到返回的列表之前通过 far.get_defining_fields()。
如果您正确理解 Python 的继承机制和 super() 的内部工作原理,这可能是一个简单的错误,但由于我显然不了解,如果有人能指出我将不胜感激这样做的正确方法。
编辑:根据 Daniel Roseman 的回答,我尝试用这种形式替换 super() 调用:return super(Foo, self).get_defining_fields( ) + self._defining_fields()
现在无限递归不再发生,但调用 bar.get_defining_fields() 时出现不同的错误:
AttributeError: 'super' object has no attribute 'get_defining_fields'
还有一些地方不对。
编辑:是的,终于弄清楚我在这里遗漏了什么。将 Daniel 的更新答案标记为已接受。
请您参考如下方法:
问题出在这里:
return super(self.__class__, self)...
self.__class__ 始终引用当前 具体类。所以在Bar中指的是Bar,在Baz中指的是Baz。因此,Bar 调用父类(super class)的方法,但 self.__class__ 仍然引用 Bar,而不是 Foo。所以你会得到一个无穷无尽的递归。
这就是为什么您必须始终在 super 中专门引用类。像这样:
return super(Foo, self)...
编辑 正确,因为只有顶级类定义了 get_defining_fields。
你的做法是错误的,真的。这根本不是 super 的工作。我认为您可能会通过 self.__class__.__mro__ 迭代获得更好的结果,这是访问父类(super class)的方法解析顺序的方式:
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
¬
