Python 类继承,__bases__, __mro__, super

Python 类继承,__bases__, __mro__, super

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Python是面向对象的编程语言,也支持类继承。

>>> class Base:

… pass

…

>>> class Derived(Base):

… pass

  

这样就定义了两个类,Derived继承了Base。issubclass(a,b)能够測试继承关系:

>>> issubclass(Derived, Base)

True

  

在Python中,每一个类有一个__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

Derived2 d;

Base &b = d;

error: ‘Base’ is an ambiguous base of ‘Derived2’

Base &b = d;

^

  

回到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__

Python 类继承,__bases__, __mro__, super

__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

Python 类继承,__bases__, __mro__, 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>>

  

參考https://docs.python.org/2/library/functions.html#super,

super(type[, object-or-type])

Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.

  

The __mro__ attribute of the type lists the method resolution search order used by both getattr() and super().

  

>>> isinstance(super(Base, d), Base)

False

>>> isinstance(super(Derived, d), Base)

False

代理对象并非类层次中某个类的实例!

  

结合多重继承来理解下__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

  

>>> class Base:

… def sayHello(self):

… print(“Base says hello”)

…

>>> class Derived(Base):

… pass

…

>>> d = Derived()

>>> d.sayHello()

Base says hello

Derived重写sayHello

>>> class Derived(Base):

… def sayHello(self):

… print(“Derived says hello”);

…

>>> d = Derived()

>>> d.sayHello()

Derived says hello

  

与參数默认值结合(联想起了C++)

>>> class Base:

… def sayHello(self, str=”Base”):

… print(“Base says: ” + str)

…

>>> class Derived(Base):

… def sayHello(self, str=”Derived”):

… print(“Dervied says: ” + str)

…

>>>

>>> d = Derived()

>>> d.sayHello()

Dervied says: Derived

>>> Base.sayHello(d)

Base says: Base

>>> super(Derived, d).sayHello()

Base says: Base

  

看一下,在基类构造函数中调用被覆盖方法的行为

>>> class Base:

… def sayHello(self):

… str = self.getStr()

… print(“Base says: ” + str)

… def getStr(self):

… return “Base”

…

>>> class Derived(Base):

… def getStr(self):

… return “Derived”

…

>>>

>>> d = Derived()

>>> d.sayHello()

Base says: Derived

>>> def Base_init(self):

… self.sayHello()

…

>>> Base.__init__ = Base_init

>>> d = Derived()

Base says: Derived

可见,行为类似Java,调用了子类的覆盖方法;

  

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/118031.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 联想笔记本BIOS设置中文_笔记本电脑 英文

    联想笔记本BIOS设置中文_笔记本电脑 英文对于很多新装系统的小伙伴们可能很多都不是太懂BIOS中都是干什么用的,小编这里给大家详细介绍一下联想笔记本的主板BIOS设置跟别的笔记本或许有些不同但大体相差不多,和大家分享一下。BIOS介绍

    2022年8月3日
  • luajit缺点_luajit和lua区别

    luajit缺点_luajit和lua区别作者:paintsnow链接:https://www.zhihu.com/question/49144449/answer/123116906来源:知乎著作权归作者所有,转载请联系作者获得授权。其实我是不主张在开发时就用LuaJIT的,因为这样会把人养懒……因为JIT的强大性能,掩盖了太多代码中的低效实现,反而最后想要提升性能已经不可能了==回到正题,我的建议是,如果

    2022年10月6日
  • 国产CPU架构、国产Linux操作系统及其国产数据库等关键应用

    国产CPU架构、国产Linux操作系统及其国产数据库等关键应用关于国产CPU架构及Linux变种编译器1、CPU架构3大阵营整合为两大CPU阵营:处理器架构_百度百科CPU架构是CPU厂商给属于同一系列的CPU产品定的一个规范,主要目的是为了区分不同类型CPU的重要标示。市面上的CPU分类主要分有两大阵营,一个是intel、AMD为首的复杂指令集CPU,另一个是以IBM、ARM为首的精简指令集CPU。两个不同品牌的CPU,其产品的架构也不相同,例如,Intel、AMD的CPU是X86架构的,而IBM公司的CPU是PowerPC架构,AR…

    2022年5月13日
  • css如何设置超链接样式

    css如何设置超链接样式css设置超链接样式是通过伪类来实现的 (1):link:设置a对象在未被访问前的样式表属性。(2):visited:设置a对象在其链接地址已被访问过时的样式表属性。(3):hover:设置对象在其鼠标悬停时的样式表属性。(4):active:设置对象在被用户激活(在鼠标点击与释放之间发生的事件)时的样式表属性。  css中关于超链接的四个属性正确顺序为:

    2022年7月19日
  • SCOM警报通知新特性:即时消息通知

    SCOM警报通知新特性:即时消息通知

    2021年7月30日
  • 飞行器pid控制(旋翼飞控)

    先说下什么是四旋翼飞行器名称:四旋翼飞行器组件:一个机架,一个陀螺仪,四个无刷直流电机,一个电池,一块单片机(能飞起来的最基本配置)原理:利用四个电机旋转产生的反作用力托起飞行器上升,利用单片机和飞行控制算法控制电机使飞行器稳定然互简单介绍下串级PID算法名字:串级PID算法作用:采集飞行器姿态角,输出调控量是飞行器稳定先说一下姿态角,现在我们想象一个平铺在空间的一个“十”字,这个字左右晃,上下晃…

    2022年4月10日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号