Reputation: 1125
I'm aware of Python name mangling, but am running into unexpected behavahior while using mutliple inheritence. Take for example:
class A(object):
def __init__(self):
self.__foo=1
def bar(self):
return self.__foo
class B(object):
pass
class C(B):
def __init__(self):
self.test=1
class D(C,A):
pass
print D().bar()
which gives the error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in bar
AttributeError: 'D' object has no attribute '_A__foo'
However, if I change the definition of "D" to:
class D(A,C):
pass
it works. Output:
1
Additionally, if I remove all the member variables from class "C", either definition of D work
class C(B):
pass
class D1(A, C):
pass
class D2(C, A):
pass
print D1().bar()
print D2().bar()
Output:
1
1
Can anyone enlighten me as to what is going on here? I would expect any of these class definitions to behave the same.
Upvotes: 1
Views: 164
Reputation: 530970
In your original definition, class D(C, A)
, the call to D.__init__
resolved to C.__init__
, so A.__init__
was never called and the __foo
attribute was never created.
In the modified definition (class D(A, C)
), the call to D.__init__
resolved to A.__init__
, which did set __foo
.
It's important to call parent constructors to ensure that your instances are properly initialized, and unlike Java, parent constructors have to be called explicitly.
For multiple inheritance, there are fewer problems if you use super
to ensure every class's __init__
method gets called.
class A(object):
def __init__(self):
super(A, self).__init__()
self.__foo = 1
def bar(self):
return self.__foo
class B(object):
pass
class C(B):
def __init__(self):
super(C, self).__init__()
self.test = 1
class D1(C,A):
pass
class D2(A,C):
pass
# Both will print 1
print D1().bar()
print D2().bar()
As long as all classes use super
properly, each method will be called once, whether the method resolution order is D1's [C, B, A, object]
or D2's [A, C, B, object]
.
Upvotes: 3