Other answers suggested adding self
to the first parameter.
But usually invocations of __init__
in parent classes are made by super
.
Consider this example:
class A(object):
def __init__(self, x):
print('__init__ is called in A')
self.x = x
class B(object):
def __init__(self, *args, **kwargs):
print('__init__ is called in B')
super(B, self).__init__(*args, **kwargs)
class AB(B, A):
def __init__(self, *args, **kwargs):
print('__init__ is called in AB')
super(AB, self).__init__(*args, **kwargs)
AB
class contains an order in which constructors and initializators should be called:
>>> AB.__mro__
(<class '__main__.AB'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
See, that first AB
's __init__
is invoked, then B
's, then A
's, and then object
's.
Let's check:
>>> ab = AB(1)
__init__ is called in AB
__init__ is called in B
__init__ is called in A
But these calls through this chain are made by super
. When we type super(AB, self)
, it means: find then next class after AB
in __mro__
chain of self
.
Then we should invoke super
in B
, looking for the next class in the chain after B
: super(B, self)
.
It's important to use super
and not call manually A.__init__(self,...)
, etc., as it may lead to problems later. Read this for more info.
So, if you stick with super
, then there is a problem. __init__
methods in your classes expect different parameters. And you can't know for sure the order in which super
will be invoking methods in these classes. The order is determined by C3 algorithm at the time of class creation. In subclasses another classes may get in-between of the call chain. So you can't have different parameters in __init__
, as in this case you will have always to consider all inheritance chain to understand how __init__
methods will be called.
For example, consider adding C(A)
and D(B)
classes and CD
subclass of them. Then A
will no longer be invoked after B
, but after C
.
class A(object):
def __init__(self, *args, **kwargs):
print('__init__ is called in A')
super(A, self).__init__(*args, **kwargs)
class B(object):
def __init__(self, *args, **kwargs):
print('__init__ is called in B')
super(B, self).__init__(*args, **kwargs)
class AB(B,A):
def __init__(self, *args, **kwargs):
print('__init__ is called in AB')
super(AB, self).__init__(*args, **kwargs)
class C(A):
def __init__(self, *args, **kwargs):
print('__init__ is called in C')
super(C, self).__init__(*args, **kwargs)
class D(B):
def __init__(self, *args, **kwargs):
print('__init__ is called in D')
super(D, self).__init__(*args, **kwargs)
class CD(D,C):
def __init__(self, *args, **kwargs):
print('__init__ is called in CD')
super(CD, self).__init__(*args, **kwargs)
class ABCD(CD,AB):
def __init__(self, *args, **kwargs):
print('__init__ is called in ABCD')
super(ABCD, self).__init__(*args, **kwargs)
>>> abcd = ABCD()
__init__ is called in ABCD
__init__ is called in CD
__init__ is called in D
__init__ is called in AB
__init__ is called in B
__init__ is called in C
__init__ is called in A
So I think it's a good idea to think about using delegation
instead of inheritance here.
class AB(object):
def __init__(self, x, y, z=0):
self.a = A(x,y)
self.b = B(z)
So, you just create a
and b
instances of A
and B
classes inside AB
object. And then may use them as you need through methods by referring to self.a
and self.b
.
To use or not delegation depends on your case which is not clear from your question. But it may be an option to consider.