I've got an inheritance chain of three classes: Baz inherits from Bar inherits from Foo. I'd like to define a method in the Foo class that, when called in a subclass, returns the output of its parent class appended with stuff of its own. This is the desired output:
>>> 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']
The problem is, I'm misunderstanding something about the use of super() in superclass methods that are called by subclasses, or some other subclassing detail. This bit works fine:
>>> print foo.get_defining_fields()
['in Foo']
But bar.get_defining_fields() produces an infinite loop, running itself until a RuntimeError is raised instead of calling out to foo.get_defining_fields and stopping there like I want it to.
Here's the code.
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']
So get_defining_fields is defined in the superclass, and the super() call within it uses self.__class__ in an attempt to pass the correct subclass name to the call in each subclass. When called in Bar, it resolves to super(Bar, self).get_defining_fields() so that the list returned by foo.get_defining_fields() would be prepended to the one returned by far.get_defining_fields().
Probably a simple mistake if you properly understand Python's inheritance mechanics and the inner workings of super(), but since I obviously don't, I'd appreciate it if someone could point me to the proper way of doing this.
EDIT: as per Daniel Roseman's answer, I tried replacing the super() call with this form: return super(Foo, self).get_defining_fields() + self._defining_fields()
Now the infinite recursion no longer occurs, but I get a different error when calling bar.get_defining_fields():
AttributeError: 'super' object has no attribute 'get_defining_fields'
Something else is still amiss.
EDIT: yep, finally figured out what I was missing here. Marked Daniel's updated answer as the accepted one.