python 面向对象之继承顺序

先来看一个经典类

class A:
    def __init__(self):
        print('A')
class B(A):
    def __init__(self):
        print('B')
class C(A):
    def __init__(self):
        print('C')
class D(B,C):
        pass

obj = D()

继承顺序如下图:

B如果有构造函数,就不会继承C的构造函数

找到第一个构造函数,就停下来,不再寻找了。

构造函数只会执行一次,先从本身找,找不到,就去上层寻找,顺序如下:

D->B->C->A

执行上面的代码,输出:B

为什么会输出B呢?往下看

将B的构造函数注释掉

class A:
    def __init__(self):
        print('A')
class B(A):
    pass
    # def __init__(self):
    #     print('B')
class C(A):
    def __init__(self):
        print('C')
class D(B,C):
        pass

obj = D()

执行输出:C

将C的构造函数注释掉

class A:
    def __init__(self):
        print('A')
class B(A):
    pass
    # def __init__(self):
    #     print('B')
class C(A):
    pass
    # def __init__(self):
    #     print('C')
class D(B,C):
        pass

obj = D()

执行输出:A

这是一个正常的寻找顺序

那么问题来了

B虽然没有构造函数,但是它继承了A,它应该从A中继续寻找构造函数才对啊

为什么去找C呢?

因为D找B的时候,B发现没有,虽然B可以从A中继承,A是更高层的,先不找它。

BC是属于同一层的(继承B,C),既然B没有,那么去找C了。

这种查询策略,叫做广度优先

先从横向策略(D->B->C->A) 查找,如果找不到了,再从上层找。

查找有很多策略

上面说到B没有,不应该就这么结束了,直接去找C了。应该从A中查找,A如果没有,再找C,顺序如下:

D->B->A->C

这种查询策略,叫做深度优先

这里没有所谓的对错,是2种查询策略,也叫继承策略

在不同的场景下,会选择不同的查询策略

从上面的例子可以看出,是属于广度优先

从python3开始,都是广度优先

使用python2执行如下代码:

class A():
    def __init__(self):
        print('A')
class B(A):
    pass
    # def __init__(self):
    #     print('B')
class C(A):
    def __init__(self):
        print('C')
class D(B,C):
        pass

obj = D()

执行输出:A

可以看出,python2使用的是 深度优先

上面的代码是经典类写法

下面看一下新式类的写法

只是将A()改为A(object)

class A(object):
    def __init__(self):
        print('A')
class B(A):
    pass
    # def __init__(self):
    #     print('B')
class C(A):
    def __init__(self):
        print('C')
class D(B,C):
        pass

obj = D()

使用python3和python2执行

结果都是C

总结:

python2 经典类是按深度优先来继承的,新式类是按广度优先来继承的

python3 经典类和新式类都是统一按广度优先来继承的

在python2中,继承效率来讲,深度优先不如广度优先

所以在python3中,统一改成广度优先

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小狼的世界

Python3.6学习笔记(二)

对于指定索引范围取值的操作,Python提供了slice方法,类似于Excel中数据透视表的切片器。

1354
来自专栏程序员互动联盟

【答疑解惑第六讲】数组与指针区别在哪?

存在问题: 小伙伴都说指针和数组不好学,总是搞不太清楚?两者到底有啥区别? 解决方案: 很多初学者朋友总是对数组和指针模模糊糊,搞不清楚。对他们之间的联系与区...

35111
来自专栏mathor

C++STL中set的使用策略(一)

1333
来自专栏编程思想之异常处理

Java编程思想之通过异常处理错误

1.     异常分为被检查的异常和运行时异常,被检查的异常在编译时被强制要求检查。异常被用来错误报告和错误恢复,但很大一部分都是用作错误报告的。

721
来自专栏运维技术迷

连仕彤博客[Python练习] 将字典扁平化

1.isinstance():判断v的类型是不是字典,如果不是就直接写入新字典; 2.递归(函数循环) 3.嵌套函数

1052
来自专栏debugeeker的专栏

《coredump问题原理探究》Linux x86版3.5节栈布局之-fomit-frame-pointer编译选项

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/detai...

752
来自专栏javathings

解释一下 HashMap 的工作原理

HashMap 是基于散列表的数据结构。所谓散列表,它通过键值对的方式存储数据,把 key 通过散列算法计算出一个存储地址,将 value 放入这个地址中。散列...

4321
来自专栏康怀帅的专栏

PHP 数据类型

PHP 支持三大类 8 种数据类型。 官方文档:http://php.net/manual/zh/language.types.php 标量(4) 布尔 boo...

3074
来自专栏Python自动化测试

python内部函数学习(九)

python提供了很多的内置函数,这些内置的函数在某些情况下,可以起到很大的作用,而不需要专门去写函数实现XX功能,直接使用内置函数就可以实现,下...

1173
来自专栏轮子工厂

嘿~这里有一份超实用的 switch 教程,真的好想推荐给你

在上次推文中介绍了关系运算符和条件运算符,今天介绍它们的好搭档,分支结构。如下图所示,左侧是顺序结构,右侧是分支结构

921

扫码关注云+社区

领取腾讯云代金券