There are numerous questions on the usage of super()
but none of them appears to answer my question.
When calling super().__init__()
from a subclass, all method calls in the super-constructor are actually taken from the subclass. Consider the following class structure:
class A(object):
def __init__(self):
print("initializing A")
self.a()
def a(self):
print("A.a()")
class B(A):
def __init__(self):
super().__init__()
# add stuff for B
self.bnum=3 # required by B.a()
def a(self):
print("B.a(), bnum=%i"%self.bnum)
b=B()
which fails with
initializing A
Traceback (most recent call last):
File "classmagic.py", line 17, in
b=B()
File "classmagic.py", line 11, in __init__
super().__init__()
File "classmagic.py", line 5, in __init__
self.a()
File "classmagic.py", line 15, in a
print("B.a(), bnum=%i"%self.bnum)
AttributeError: 'B' object has no attribute 'bnum'
Here I call the super constructor in B()
to initialize some basic structure (some of which is executed as an own function a()
). However, if I override the a()
function as well, this implementation is used when calling A
's constructor which fails because A
knows nothing about B
and may use different internal variables.
This may or may not be intuitive, but what do I have to do when I want all methods in A
only to have access to the functions implemented there?
If your code has to call specific private methods that cannot be overridden, use a name that starts with two underscores:
Python "mangles" such method names by adding in the class name (plus an underscore) to minimize the chances subclasses overwrite them with their own versions.
The PEP 8 Python Style Guide has this to say about private name mangling:
Consider this call:
which is what happens when you call
super().__init__()
. This, in turn, callsself.a()
, which is of course the functiona
of classB
and notA
becauseself
is of classB
. As Martijn stated, you can use dual-underscore names, or explicitly use the class name, but otherwise it is impossible to call an overridden method from a superclass.If we go through the instanciation steps of
B
:super(B,self).__init__
, that is,A.__init__
self.a()
, that is,B.a()
in our case,self.bnum
Except that
bnum
hasn't been defined yet... So,AttributeError
.For this particular case, it's just enough to define your
bnum
inB.__init__
before callingsuper(B,self).__init__
Before going the dark, dark path of name mangling, you may want to just take the time to organize the code of your subclass: should it be performed before the parent's, to initialize some special variables, or after the parent's, to replace some defaults ?
Rather than calling
self.a()
, you'll need to useA.a(self)
. But this is not common to do for all methods on a particular class and you should really re-evaluate whetherB
should inherit fromA
.