Python多重继承说明及应用
2017-11-27 18:02
204 查看
Python中没有接口的概念,替代之的是多重继承。而引入多重继承之后,一个新的问题是多个父类之间的继承顺序和方法调用顺序。比如:子类中调用的方法在多个父类中都存在的时候,到底会调用哪个父类的方法?(显然不会把所有父类的方法都调用一遍)
深度优先搜索(DFS)
广度优先搜索(BFS)
深度优先搜索图解如下:
这种查找方式的缺点:
棱形继承时可能会出现父类访问优先于子类访问。如上图中的父类D就优于子类C先被访问到。这会导致子类C中的覆盖方法无法被访问到。
广度优先搜索图解如下:
这种查找方式的缺点:
在正常继承时没有按照继承的单调性来查找。
为了解决DFS和BFS的缺陷问题,Python中使用了C3算法,经过调整之后多重继承的查找方式如下:
C3算法结合了DFS和BFS的优点,当正常继承时使用DFS,当为棱形继承时则使用BFS(DFS是Python2.2以前的算法,Python2.2同时使用了DFS(经典类)、BFS算法(新式类),Python2.3及之后使用C3算法)。最后推测下图中MRO的顺序为何?
经典类
新式类
经典类是Python一直都存在的,而新式类是Python2.2中才加入的,而Python3.0中只支持新式类。它们的各自定义如下:
新式类也可以使用经典类的方式调用父类方法,另外还可以使用super类来实现。具体如下:
之所以给新式类提供了super类来调用父类的方法,是因为前面介绍的棱形继承的场景。如果使用经典类的方式调用,则公共父类*Base会被调用两次;而如果使用super类的方式则只会调用一次。
另外,在类创建时默认不创建__init__方法时,经典类与新式类的行为也不一样。经典会只调用第一个父类的__init__方法,而新式类与显式使用super的效果是一样的。也就是说如果你使用的是新式类,那么不是初始化__init__也会初始化所有的父类方法。而一旦你定义了__init__方法,则需要自己显式的初始化父类方法。
理解MRO
如果把单重继承理解为是链表结构,那么多重继承则可以认为是树状结构。所以多重继承的向上搜索的规则有2种实现方式:深度优先搜索(DFS)
广度优先搜索(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 继承多重继承
- 洗礼灵魂,修炼python(35)--面向对象编程(5)—多重继承,组合
- python3中多重继承的问题
- Python类的多重继承问题深入分析
- python进阶15:继承、多态和多重继承
- python多重继承
- Python多重继承的异构构造器
- Python面向对象——多重继承大揭秘
- python学习——多重继承
- python多重继承新算法C3介绍
- Python多重继承引发的问题——牛逼的super
- Python多重继承的方法解析执行顺序实例分析
- 7 python 动态绑定,@property的使用__slots_限制class的属性以及多重继承
- python 27 super继承(解决多重继承时,老办法init父类多次的问题)
- python多重继承
- python多重继承
- python多重继承实例
- python多重继承实例
- python多重继承C3算法
- python 27 super继承(解决多重继承时,老办法init父类多次的问题)