Reputation: 566
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
Upvotes: 2
Views: 1081
Reputation: 532418
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 to A
, so A.__init__
is called with foo=3
and bar=9
.A.__init__
, super()
resolves to B
, so B.__init__
is called with bar=9
.B.__init__
, super()
resolves to object
, so object.__init__
is called with no arguments (kwargs
being empty)object.__init__
returns, self.bar
is set to bar
B.__init__
returns, self.foo
is set to foo
A.__init__
returns, C.__init__
finishes upOK, 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.
Upvotes: 4
Reputation: 6458
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')
Upvotes: 0