>>> class Base:
... pass
...
>>> class Derived(Base):
... pass
每个类有一个__bases__属性,列出其基类
>>> Derived.__bases__
(<class '__main__.Base'>,)
同C++,Python支持多重继承;
>>> class Derived2(Derived,Base):
... pass
...
Derived2继承了Derived和Base(实际中不会这么写)
>>> Derived2.__bases__
(<class '__main__.Derived'>, <class '__main__.Base'>)
这里,Derived,和Base的顺序不能搞反
>>> class Derived2(Base, Derived):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Cannot create a consistent method resolution
order (MRO) for bases Derived, Base
插一段C++
C++代码 |
class Base{ };
class Derived: public Base{ };
class Derived2: public Base, public Derived{ };
int main(){ } |
mulit_inherit.cc:7:7: warning: direct base 'Base' inaccessible in 'Derived2' due to ambiguity [enabled by default] class Derived2: public Base, public Derived{ ^ |
mulit_inherit.cc:7:7: warning: direct base 'Base' inaccessible in 'Derived2' due to ambiguity [enabled by default] class Derived2: public Derived, public Base{ ^ |
可以见,C++并没有限制书写顺序。warning指示了Derrived2中不能访问Base
回到Python继承,Derived2是Derived的子类,也是Base的子类
>>> issubclass(Derived2, Base)
True
>>> issubclass(Derived2, Derived)
True
__bases__类似于Javascript中Object对象的__proto__,是实现继承的基础,不同在于:__bases__不可修改,而且__bases__是类的属性而不是对象属性(Javascript是基于对象的语言);
>>> d = Derived2()
>>> d.__bases__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Derived2' object has no attribute '__bases__'
>>> d.__class__
<class '__main__.Derived2'>
>>> d.__class__.__bases__
(<class '__main__.Derived'>, <class '__main__.Base'>)
对象的__class__属性指明了所属类型;
>>> [].__class__
<class 'list'>
>>> ().__class__
<class 'tuple'>
>>> 1.__class__
File "<stdin>", line 1
1.__class__
^
SyntaxError: invalid syntax
>>> type(1)
<class 'int'>
在Python中1,是对象还是基本类型?
__mro__
__mro__给出了method resolution order,即解析方法调用的顺序。
>>> Derived.__mro__
(<class '__main__.Derived'>, <class '__main__.Base'>, <class 'object'>)
>>> Derived2.__mro__
(<class '__main__.Derived2'>, <class '__main__.Derived'>, <class '__main__.Base'>, <class 'object'>)
看上去和__bases__相像,只是最后面多了个<class 'object'>
super
super函数可以用于调用父类的方法,而后者可能被子类覆盖;类似在java中的作用,但使用起来更复杂些。
>>> class Base:
... pass
...
>>> class Derived(Base):
... pass
...
>>> class Derived2(Derived)
File "<stdin>", line 1
class Derived2(Derived)
^
SyntaxError: invalid syntax
>>> class Derived2(Derived):
... pass
...
>>> d = Derived2()
>>> super(Derived2, d)
<super: <class 'Derived2'>, <Derived2 object>>
>>> super(Derived, d)
<super: <class 'Derived'>, <Derived2 object>>
>>> super(Base, d)
<super: <class 'Base'>, <Derived2 object>>
结合多重继承来理解下__mro__和super
class A:
def __init__(self):
print('enter __init__@A')
super(A,self).__init__()
print('exit __init__@A')
class B(A):
def __init__(self):
print('enter __init__@B')
super(B,self).__init__()
print('exit __init__@B')
class C(A):
def __init__(self):
print('enter __init__@C')
super(C,self).__init__()
print('exit __init__@C')
class D(A):
def __init__(self):
print('enter __init__@D')
super(D,self).__init__()
print('exit __init__@D')
class E(B,C):
def __init__(self):
print('enter __init__@E')
super(E,self).__init__()
print('exit __init__@E')
class F(E,D):
def __init__(self):
print('enter __init__@F')
super(F,self).__init__()
print('exit __init__@F')
if __name__ == '__main__':
A()
print(A.__mro__)
B()
print(B.__mro__)
C()
print(C.__mro__)
D()
print(D.__mro__)
E()
print(E.__mro__)
F()
print(F.__mro__)
运行结果
enter __init__@A exit __init__@A (<class '__main__.A'>, <class 'object'>) enter __init__@B enter __init__@A exit __init__@A exit __init__@B (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>) enter __init__@C enter __init__@A exit __init__@A exit __init__@C (<class '__main__.C'>, <class '__main__.A'>, <class 'object'>) enter __init__@D enter __init__@A exit __init__@A exit __init__@D (<class '__main__.D'>, <class '__main__.A'>, <class 'object'>) enter __init__@E enter __init__@B enter __init__@C enter __init__@A exit __init__@A exit __init__@C exit __init__@B exit __init__@E (<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) enter __init__@F enter __init__@E enter __init__@B enter __init__@C enter __init__@D enter __init__@A exit __init__@A exit __init__@D exit __init__@C exit __init__@B exit __init__@E exit __init__@F (<class '__main__.F'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>) |
观察到,super的执行路径和类的__mro__列举的类顺序吻合;而__mro__的顺序可以看作是深搜的结果
A
/ | \
B C D
\ / /
E /
\ /
F
class E(B, C)中,B和C不是基-派生类关系,E.__mro__中B在C之前,需要注意;
转载自原文链接, 如需删除请联系管理员。
原文链接:Python 类继承,__bases__, __mro__, super,转载请注明来源!