且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

python类中的super,原理如何?MRO是什么东东?

更新时间:2022-08-21 22:30:44

下面这个URL解释得比较清楚。

http://python.jobbole.com/86787/?utm_source=group.jobbole.com&utm_medium=relatedArticles

================

首先得说明的是,Python的类分为经典类 和 新式类
经典类是python2.2之前的东西,但是在2.7还在兼容,但是在3之后的版本就只承认新式类了
新式类在python2.2之后的版本中都可以使用

经典类和新式类的区别在于:

  1. 经典类是默认没有派生自某个基类的,而新式类是默认派生自object这个基类的:

 

2.经典类在类多重继承的时候是采用从左到右深度优先原则匹配方法的..而新式类是采用C3算法(不同于广度优先)进行匹配的

3.经典类是没有__MRO__instance.mro()调用的,而新式类是有的.

为什么不用经典类,要更换到新式类

因为在经典类中的多重继承会有些问题…可能导致在继承树中的方法查询绕过后面的父类:

在经典类中,你如果要访问父类的话,是用类名来访问的..

这样子看起来没三问题,但是如果类的继承结构比较复杂,会导致代码的可维护性很差..
所以新式类推出了super这个东西…

事实上,对于你定义的每一个类,Python 会计算出一个方法解析顺序(Method Resolution Order, MRO)列表它代表了类继承的顺序,我们可以使用下面的方式获得某个类的 MRO 列表:

那这个 MRO 列表的顺序是怎么定的呢,它是通过一个 C3 线性化算法来实现的,这里我们就不去深究这个算法了,感兴趣的读者可以自己去了解一下,总的来说,一个类的 MRO 列表就是合并所有父类的 MRO 列表,并遵循以下三条原则:

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

***实现:

  1. 避免多重继承
  2. super使用一致
  3. 不要混用经典类和新式类
  4. 调用父类的时候注意检查类层次

小结

  • 事实上,super 和父类没有实质性的关联。
  • super(cls, inst) 获得的是 cls 在 inst 的 MRO 列表中的下一个类。

测试代码:

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


class Base(object):
    def __init__(self):
        print 'enter base'
        print 'leave base'


class A(Base):
    def __init__(self):
        print 'enter A'
        super(A, self).__init__()
        print 'leave A'


class B(Base):
    def __init__(self):
        print 'enter B'
        super(B, self).__init__()
        print 'leave B'


class C(A, B):
    def __init__(self):
        print 'enter C'
        super(C, self).__init__()
        print 'leave C'


print C.mro()
print C()

 

输出:

python类中的super,原理如何?MRO是什么东东?