问题
I was trying to learn the concepts of multiple-inheritance in Python. Consider a class Derv
derived from two classes, Base1
and Base2
. Derv
inherits members from the first base class only:
class Base1:
def __init__(self):
self.x=10
class Base2:
def __init__(self):
self.y=10
class Derv (Base1, Base2):
pass
d = Derv()
print (d.__dict__)
The result is { 'x' : 10 }
and reversing the order of inheritance gives only { 'y' : 10 }
.
Shouldn't the derived class inherit attributes from both the base classes?
回答1:
I don't fully understand why it's like this, but I can tell you how to fix it:
For some reason, Python only calls the __init__
method of one of it's parents. However, this fixes your problem:
class Base1:
def __init__(self):
super().__init__()
print('b1')
self.x=10
class Base2:
def __init__(self):
super().__init__() # This line isn't needed. Still not sure why
print('b2')
self.y=10
class Derv (Base1, Base2):
def __init__(self):
super().__init__()
d = Derv()
print (d.__dict__)
'b2'
'b1'
{'y': 10, 'x': 10}
Update, adding print statements actually sheds some light on the situation. For example,
class Base1:
def __init__(self):
print('Before Base1 call to super()')
super().__init__()
print('b1')
self.x=10
class Base2:
def __init__(self):
print('Before Base2 call to super()')
super().__init__() # No remaining super classes to call
print('b2')
self.y=10
class Derv (Base1, Base2):
def __init__(self):
super().__init__()
d = Derv()
print (d.__dict__)
'Before Base1 call to super()' # Just before the call to super
'Before Base2 call to super()' # Just before call to super (but there are no more super classes)
'b2' # Calls the remaining super's __init__
'b1' # Finishes Base1 __init__
{'y': 10, 'x': 10}
回答2:
When a class inherits from multiple superclasses, and there are 2 or more conflicting methods, the one in the first listed class is called. Because both Base1
and Base2
define __init__
, the version of __init__
in the first listed class is called, therefore not defining both of the attributes.
回答3:
This is explained better in Python docs.
For most purposes, in the simplest cases, you can think of the search for attributes inherited from a parent class as depth-first, left-to-right, not searching twice in the same class where there is an overlap in the hierarchy. Thus, if an attribute is not found in DerivedClassName, it is searched for in Base1, then (recursively) in the base classes of Base1, and if it was not found there, it was searched for in Base2, and so on.
Then, as __init__
is first find in your left class, it won't look for others. As other users explained, super()
should be used to let Python know how to look for other __init__
methods.
回答4:
You could create objects with class attributes like this:
class Base1:
x=10
class Base2:
y=10
Then your Derv class would indeed inherit both properties.
class Derv (Base1, Base2):
pass
d = Derv()
print(d.x, d.y) # prints: 10, 10
The __init__
method is called when you create an instance of an object (ie, d = Derv()
). An object can only have one version of a given method, so your Derv class only inherits the first one.
来源:https://stackoverflow.com/questions/52959041/multiple-inheritance-the-derived-class-gets-attributes-from-one-base-class-only