码迷,mamicode.com
首页 > 其他好文 > 详细

🍔类的菱形继承问题

时间:2020-12-30 10:57:11      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:分支   pass   lock   深度   python3   tee   多个   git   nim   

一.类的分类

在前面一章我们简单介绍了一些类的分类

1.新式类

  • 继承了 object 的类以及该类的子类, 都是新式类 (Python3中统一都是新式类)
  • Python3 中如果一个类没有继承任何类, 则默认会继承 object 类, 也就是Python3中所有的类都是新式类
??在"Python3"中
class Default:  # 默认继承"object"
    pass

print(Default.__bases__)  # (<class ‘object‘>,)

2.经典类

  • 没有继承 object 的类以及该类的子类, 都是经典类 (只有Python2中才区分新式类和经典类)
  • Python2 中如果一个类没有继承任何类, 它不会继承object 类, 所以Python2 中才有经典类
??在"Python2"中
class Default(object):  # 新式类
    pass

class Animal:  # 经典类
    pass

??"Python2"中"print"语法
print Default.__bases__  # (<class ‘object‘>,)
print Animal.__bases__   # ()

ps : 新式类与经典类的属性查找顺序是不一样的


二.菱形继承问题

上面说到Python支持多继承, 但新式类与经典类的属性查找顺序是不一样的

java语言中,它不支持多继承,只支持继承一个父类

python语言,支持多继承,比如 A(B,C,D)

1.非菱形结构

  • 非菱形结构下, 经典类与新式类的属性查找顺序是一样的

  • 如果继承关系为非菱形结构,则会按照先找 B 这一条分支,然后再找 C 这一条分支,最后找 D 这一条分支的顺序直到找到我们想要的属性

  • 非菱形结构 (两条查询路径最后分别继承了 F1 和 F4)

技术图片

class F1:
    def s1(self):
        print(‘F1:s1‘)
    def s2(self):
        print(‘F1:s2‘)

class F2(F1):
    # def s1(self):
    #     print(‘F2:s1‘)
    def s2(self):
        print(‘F2:s2‘)

class F4():
    def s1(self):
        print(‘F4:s1‘)
    def s2(self):
        print(‘F4:s2‘)

class F3(F2,F4):
    def s1(self):
        super().s1()  # 调用父类的s1方法,到底使用了哪个父类的s1
    def s2(self):
        print(‘F3:s2‘)


f1 = F3()
f1.s1()  # F1:s1
  • 查找顺序 : F3 ===> F2 ===> F1

2.菱形结构

  • 如果继承关系为菱形结构,即子类的父类最后继承了同一个类,那么属性的查找方式有两种:
    • 新式类----->广度优先
    • 经典类----->深度优先

1、新式类----->广度优先

  • 不找多各类最后继承的同一个类,直接去找下一个父类
  • __mro__ : 只有新式类才有的属性, 可查看属性查找的顺序

技术图片

class G(object):
    # def test(self):
    #     print(‘from G‘)
    pass

class E(G):
    # def test(self):
    #     print(‘from E‘)
    pass

class B(E):
    # def test(self):
    #     print(‘from B‘)
    pass

class F(G):
    # def test(self):
    #     print(‘from F‘)
    pass

class C(F):
    # def test(self):
    #     print(‘from C‘)
    pass

class D(G):
    # def test(self):
    #     print(‘from D‘)
    pass

class A(B, C, D):
    def test(self):
        print(‘from A‘)

obj = A()
obj.test()
print(A.__mro__)
‘‘‘查找顺序
(<class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>, <class ‘__main__.C‘>, <class ‘__main__.F‘>, <class ‘__main__.D‘>, <class ‘__main__.G‘>, <type ‘object‘>)
‘‘‘

2、经典类----->深度优先

  • 从左到右选路, 一条路走到黑

技术图片

#coding:utf-8
# python2 解释器

class G():
    pass
    def test(self):
        print(‘G---test‘)

class F(G):
    pass
    # def test(self):
    #     print(‘FFF---test‘)
class E(G):
    pass
    # def test(self):
    #     print(‘EEE---test‘)
class D(G):
    pass
    # def test(self):
    #     print(‘DDD---test‘)
class B(E):
    pass
    # def test(self):
    #     print(‘BBB---test‘)
class C(F):
    pass
    # def test(self):
    #     print(‘CCC---test‘)

class A(B,C,D):
    pass
    # def test(self):
    #     print(‘AAA---test‘)

a=A()
a.test()  # G---test

三.小示例

1.新式类

  • 菱形结构示例 (子类最后继承了同样的类, 都继承了 A1 和 A2), 可以看成两个菱形

技术图片

class A1:
    def foo(self):
        print(‘A1_foo‘)

class A2:
    def foo(self):
        print("A2_foo")

    def bar(self):
        print("A2_bar")

class B1(A1, A2):
    pass

class B2(A1, A2):
    def bar(self):
        print("B2_bar")

class C(B1, B2):
    pass

c = C()
c.foo()  # A1_foo
c.bar()  # B2_bar

print(C.__mro__)
‘‘‘输出
(<class ‘__main__.C‘>, <class ‘__main__.B1‘>, <class ‘__main__.B2‘>, <class ‘__main__.A1‘>, <class ‘__main__.A2‘>, <class ‘object‘>)
‘‘‘
  • c.foo() 的查找顺序 : C ==> B1 ===> B2 ==> A1
  • c.bar() 的查找顺序 : C ==> B1 ==> B2

2.经典类

技术图片

#coding:utf-8
# python2.7 解释器
class A1():
    def foo(self):
        print ‘A1_foo‘

class A2():
    def foo(self):
        print "A2_foo"

    def bar(self):
        print "A2_bar"

class B1(A1, A2):
    pass

class B2(A1, A2):
    def bar(self):
        print "B2_bar"

class C(B1, B2):
    pass

c = C()
c.foo()  # A1_foo
c.bar()  # A2_bar
  • c.foo() 的查找顺序 : C ==> B1 ===> A1
  • c.bar() 的查找顺序 : C ==> B1 ==> A1 ===> A2

四. c3 算法与 mro

1.简介

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止

而这个MRO列表的构造是通过一个C3线性化算法来实现的

我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则 :

  • 子类会先于父类被检查
  • 多个父类会根据它们在列表中的顺序被检查
  • 如果对下一个类存在两个合法的选择,选择第一个父类

2.__mro__ 方法使用

其实上面我们已经使用了这种方法, 下面再补充一点

  • 只有新式类才可以使用 (Python2中的类如果没继承object就无法使用)
  • [类名]__mro__ : 打印属性查找顺序, 是一个元组
  • [类名].mro() : 打印属性查找顺序, 是一个列表
??Python2 中
#coding:utf-8

class C(object):  # 继承object类,如果不继承,调用 mro 方法会报错 
    def run(self):
        print "run_C"

class B(C):
    pass

class A(B):
    pass

a = A()
a.run()  # run_C
print A.__mro__  
# (<class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <type ‘object‘>)

print A.mro()  
# [<class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <type ‘object‘>]

??Python3 中
class C:  # 已经自动继承了object类
    def run(self):
        print("run_C")

class B(C):
    pass

class A(B):
    pass

a = A()
a.run()  # run_C
print(A.__mro__)
# (<class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘object‘>)

print(A.mro())
# [<class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘object‘>]

🍔类的菱形继承问题

标签:分支   pass   lock   深度   python3   tee   多个   git   nim   

原文地址:https://www.cnblogs.com/songhaixing/p/14186316.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!