Reputation: 662
In a method in a class, I need to call super() of the class where the method is defined, not the class of the object. I specifically care about Python 2.x, but 3.x solutions are welcome.
I want to have generic boilerplate that can be used throughout a project, where one class inherits from another, to an unknown depth. To avoid recursion errors, I need to call the parent class of the current class where the code is defined, not the parent of the self
object. There are a number of places in each module where the current class name is referenced, as many methods are extended, and each extended method may call the parent class method.
Here's demo that fails:
#!/usr/bin/env python
from inspect import stack
class Foo(object):
def __init__(self):
print "Foo.__init__()"
print "file: %s" % __file__
print "class: %s" % self.__class__.__name__
print "stack: %s" % stack()[0][3]
print
class Bar(Foo):
def __init__(self):
print "Bar.__init__()"
super(type(self), self).__init__()
class Baz(Bar):
pass
foo = Foo()
bar = Bar()
baz = Baz()
Here is the result:
Foo.__init__()
file: ./class.py
class: Foo
stack: __init__
Bar.__init__()
Foo.__init__()
file: ./class.py
class: Bar
stack: __init__
Bar.__init__()
Bar.__init__()
# snip several hundred lines
Bar.__init__()
Bar.__init__()
Traceback (most recent call last):
File "./class.py", line 24, in <module>
baz = Baz()
File "./class.py", line 16, in __init__
super(type(self), self).__init__()
# snip several hundred lines
File "./class.py", line 16, in __init__
super(type(self), self).__init__()
File "./class.py", line 16, in __init__
super(type(self), self).__init__()
RuntimeError: maximum recursion depth exceeded while calling a Python object
Upvotes: 1
Views: 59
Reputation: 152667
As you already found out using type(self)
leads to recursions because Baz.__init__
is directed to Bar.__init__
but in there you want to call super(Baz, self).__init__
which is again Bar.__init__
so you end up with an infinite recursion.
Generally it's convention that you only call the parent without knowing on which class-instance you've called it because otherwise you'll need to really know and fix your MRO
. You can always find out which child-class called the method with self.__class__
or self.__class__.__name__
Resolving it is quite simple: Replace your super
-calls with:
super(Bar, self).__init__()
in python3 to avoid these (mostly unnecessary) hardcoding of classes in super it's also possible to use:
super().__init__()
That will always call the method on the next parent class that implements it. There are really seldom cases where the parent class of your current class is not the next parent class resolved by the super call.
The output then becomes (missing __file__
):
Foo.__init__()
class: Foo
stack: __init__
Bar.__init__()
Foo.__init__()
class: Bar
stack: __init__
Bar.__init__()
Foo.__init__()
class: Baz
stack: __init__
Upvotes: 1