首页 » 技术分享 » Python 类继承,__bases__, __mro__, super

Python 类继承,__bases__, __mro__, super

 

>>> 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,转载请注明来源!

0