Python多重继承说明及应用 - Go语言中文社区

Python多重继承说明及应用


Python中没有接口的概念,替代之的是多重继承。而引入多重继承之后,一个新的问题是多个父类之间的继承顺序和方法调用顺序。比如:子类中调用的方法在多个父类中都存在的时候,到底会调用哪个父类的方法?(显然不会把所有父类的方法都调用一遍)

 

理解MRO

如果把单重继承理解为是链表结构,那么多重继承则可以认为是树状结构。所以多重继承的向上搜索的规则有2种实现方式:

  1. 深度优先搜索(DFS)
  2. 广度优先搜索(BFS)

深度优先搜索图解如下:

这种查找方式的缺点:

棱形继承时可能会出现父类访问优先于子类访问。如上图中的父类D就优于子类C先被访问到。这会导致子类C中的覆盖方法无法被访问到。

 

广度优先搜索图解如下:

这种查找方式的缺点:

在正常继承时没有按照继承的单调性来查找。

 

为了解决DFS和BFS的缺陷问题,Python中使用了C3算法,经过调整之后多重继承的查找方式如下:

C3算法结合了DFS和BFS的优点,当正常继承时使用DFS,当为棱形继承时则使用BFS(DFS是Python2.2以前的算法,Python2.2同时使用了DFS(经典类)、BFS算法(新式类),Python2.3及之后使用C3算法)。最后推测下图中MRO的顺序为何?

 

父类方法显式调用

Python2.7版本中,类的定义有2种方式:

 

  • 经典类
  • 新式类

 

经典类是Python一直都存在的,而新式类是Python2.2中才加入的,而Python3.0中只支持新式类。它们的各自定义如下:

 

#!/usr/bin/env python
#coding:utf-8

class oldClass:        #经典类
	pass
	
class newClass(object):   #新式类
	pass
	
print type(oldClass)     #classobj
print type(newClass)     #type

从代码可以知道显式的继承自object的则为新式类,不继承任何其它类的为经典类。经典类与新式类除了定义上有区别,在显式调用父类方法时也有些许不同。经典类调用父类代码如下:

 

 

#!/usr/bin/python
#encoding: utf-8
import inspect

class oldBase(object):
    def __init__(self):
        print '%s' % oldBase.__name__

class oldParentA(oldBase):
    def __init__(self):
        print '%s' % oldParentA.__name__
        oldBase.__init__(self)

class oldParentB(oldBase):
    def __init__(self):
        print '%s' % oldParentB.__name__
        oldBase.__init__(self)

class oldChild(oldParentA, oldParentB):
    def __init__(self):
        print '%s' % oldChild.__name__
        oldParentA.__init__(self)
        oldParentB.__init__(self)

if __name__ == '__main__':
    print inspect.getmro(oldChild)     #打印mro中父类的查找顺序
    n = oldChild()

 

新式类也可以使用经典类的方式调用父类方法,另外还可以使用super类来实现。具体如下:

 

#!/usr/bin/python
#encoding: utf-8
class newBase(object):
    def __init__(self):
        print '%s' % newBase.__name__

class newParentA(newBase):
    def __init__(self):
        print '%s' % newParentA.__name__
        super(newParentA, self).__init__()

class newParentB(newBase):
    def __init__(self):
        print '%s' % newParentB.__name__
        super(newParentB, self).__init__()

class newChild(newParentA, newParentB):
    def __init__(self):
        print '%s' % newChild.__name__
        super(newChild, self).__init__()

if __name__ == '__main__':
    print newChild.__mro__          #打印mro中父类的查找顺序
    n = newChild()

 

之所以给新式类提供了super类来调用父类的方法,是因为前面介绍的棱形继承的场景。如果使用经典类的方式调用,则公共父类*Base会被调用两次;而如果使用super类的方式则只会调用一次。

 

另外,在类创建时默认不创建__init__方法时,经典类与新式类的行为也不一样。经典会只调用第一个父类的__init__方法,而新式类与显式使用super的效果是一样的。也就是说如果你使用的是新式类,那么不是初始化__init__也会初始化所有的父类方法。而一旦你定义了__init__方法,则需要自己显式的初始化父类方法。

多重继承应用

 

 

更多关于Python的知识,请扫描如下二维码哦!

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/five3/article/details/78646978
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-01 21:27:15
  • 阅读 ( 993 )
  • 分类:Go应用

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢