I am trying to figure how to use super() to initialize the parent class one by one based on condition.
class A:
def __init__(self, foo):
self.foo = foo
class B:
def __init__(self, bar):
self.bar == bar
class C(A,B):
def __init__(self):
#Initialize class A first.
#Do some calculation and then initialize class B
How do I use super() in class C such that it only initializes class A first, then I do some calc and call super() to initialize class B
2 Answers 2
You cannot do what you ask for in C.__init__, as super doesn't give you any control over which specific inherited methods get called, only the order in which they are called, and that is controlled entirely by the order in which the parent classes are listed.
If you use super, you need to use it consistently in all the classes. (That's why it's called cooperative inheritance.) Note this means that C cannot inject any code between the calls to A.__init__ and B.__init__.
__init__ is particularly tricky to implement correctly when using super, because a rule of super is that you have to expected arbitrary arguments to be passed, yet object.__init__() doesn't take any arguments. You need each additional argument to be "owned" by a particular root class that is responsible for removing it from the argument list.
class A:
def __init__(self, foo, **kwargs):
# A "owns" foo; pass everything else on
super().__init__(**kwargs)
self.foo = foo
class B:
def __init__(self, bar, **kwargs):
# B "owns" bar; pass everything else on
super().__init__(**kwargs)
self.bar = bar
class C(A,B):
def __init__(self):
# Must pass arguments expected by A and B
super().__init__(foo=3, bar=9)
The MRO for C is [A, B, object], so the call tree looks something like this:
C.__init__is called with no argumentssuper()resolves toA, soA.__init__is called withfoo=3andbar=9.- In
A.__init__,super()resolves toB, soB.__init__is called withbar=9. - In
B.__init__,super()resolves toobject, soobject.__init__is called with no arguments (kwargsbeing empty) - Once
object.__init__returns,self.baris set tobar - Once
B.__init__returns,self.foois set tofoo - Once
A.__init__returns,C.__init__finishes up
OK, the first sentence isn't entirely true. Since neither A nor B, as currently written, use super, you might be able to assume that an appropriate use of super will simply call one parent function and immediately return.
class A:
def __init__(self, foo):
self.foo = foo
class B:
def __init__(self, bar):
self.bar == bar
class C(A,B):
def __init__(self):
super(A, self).__init__(foo=3)
# Do some calculation
super(B, self).__init__(bar=9)
I'm not entirely certain, though, that this doesn't introduce some hard-to-predict bugs that could manifest with other subclasses of A, B, and/or C that attempt to use super properly.
Comments
You can actually refer the base classes explicitly:
class A:
def __init__(self, foo):
self.foo = foo
class B:
def __init__(self, bar):
self.bar == bar
class C(A,B):
def __init__(self):
A.__init__(self, 'foovalue')
# Do some calculation
B.__init__(self, 'barvalue')
2 Comments
super()super() returns a proxy object that allows you to make method calls to the parent classes by the order defined in __mro__ attribute. Since you want to explicitly initialize class A and class B, the only way is to call each initializer method explicitly - you need to tell Python which initializer you want to call.
super().foo()is that it isn't just a shortcut forfor cls in parent_classes: cls.foo(self).