python---方法解析顺序MRO(Method Resolution Order)<以及解决类中super方法>
MRO了解:
对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就需要对当前类和基类进行搜索以确定方法所在的位置。
而搜索的顺序就是所谓的「方法解析顺序」(Method Resolution Order,或MRO)。
对于只支持单继承的语言来说,MRO 一般比较简单;而对于 Python 这种支持多继承的语言来说,MRO 就复杂很多。
而具体讨论MRO,我们需要针对不同python版本中的MRO进行解析
经典类:DFS深度优先搜索(Python2.2以前的版本)
新式类:BFS广度优先搜索(Python2.2中提出,在与经典类共存的情况下,是否继承object是他们的区分方式)
新式类C3算法:Python2.3提出(也是现在Python3唯一支持的方式)
对于下面讨论的类的多重继承:我们讨论两种情况。
一:经典类(深度优先搜索)
在经典类中,没有__mro__属性可以去查看MRO的顺序,但是,可以使用inspect模块中getmro方法
import inspect
inspect.getmro(类名)
(一)正常继承模式

在正常继承模式下,不会引起任何问题
(二)交叉继承模式

缺点:C类原本是D的子类,若是在C中对D的某个方法进行了重载(B类没有进行重载),那么我们在A中所希望使用的是C中的重载方法,
但是由于查找顺序是A->B->D->C,所以对于在C类中的重载方法,会在结果D时被过滤(因为在D中查找到该方法就停止了),导致永远无法访问到C中的重载方法
import inspect class D:
def foo(self):
print("D.foo") class C(D):
def foo(self):
print("C.foo") class B(D):
pass class A(B,C):
pass print(inspect.getmro(A)) #A->B->D->C
obj = A()
obj.foo() #D.foo
代码演示
二:新式类(广度优先搜索)
(一)正常继承方式

缺点:B继承于D,若是D中实现了某个方法,B可以去调用他,但是C中也自定义了一个同名方法。那么B会获取到C中的方法就结束了。这可不是我们所希望出现的
class E(object):
pass class D(object):
def foo(self):
print("D.foo") class C(E):
def foo(self):
print("C.foo") class B(D):
pass class A(B,C):
pass print(A.__mro__) #A->B->C->D->E
obj = A()
obj.foo() #C.foo
代码演示
(二)交叉继承方式

在交叉继承的方式下,不会出现任何问题
三:新式类(C3算法实现:看起来就是将上面两者的优点结合了。所以在Python3中全部都是新式类,不需要object继承)
(一)正常继承方式

(二)交叉继承方式

在python3中这种MRO方法是唯一使用的。
四:C3算法了解
推文:C3算法了解
推文:C3算法了解(这个更加详细)
但是上面两个对于MRO的计算方法都有错误处,不过其中第二篇“C3算法了解”的评论给出了详细的解法。下面我也写出这两篇文章中的具体解法
注意:我们把类 C 的线性化(MRO)记为 L[C] = [C1, C2,…,CN]。其中 C1 称为 L[C] 的头,其余元素 [C2,…,CN] 称为尾
L[object] = [object]
L[C(B1,B2,...,B(N-1),BN)] = [C] + merge(L[B1]+L[B2]+...+L[B(N-1)]+L[BN], [B1,B2,...,B(N-1),BN]) #这种解法是正确的
其他地方可以看上面两篇推文即可(第二篇更加详细)
步骤:
1.检查第一个列表的头元素(如 L[B1] 的头),记作 H。
2.若 H 未出现在其它列表的尾部,则将其输出,并将其从所有列表中删除,然后回到步骤1;否则,取出下一个列表的头部记作 H,继续该步骤。(重点)
3.重复上述步骤,直至列表为空或者不能再找出可以输出的元素。如果是前一种情况,则算法结束;如果是后一种情况,说明无法构建继承关系,Python 会抛出异常。
(一)推文一:案例推导(其中o代表object类)

解题步骤:

(二)推文二:案例推导

解题步骤:

可能你发现这种解法,和两篇推文中的答案一致。但是你向下看,在super方法中提到一个错误案例,再去使用这种方法和推文中的方法,就知道该如何使用了。
下面讨论__init__和super()方法的关系
一:在单继承中super方法和__init__使用时功能上基本是无差别的
class A(object):
def __init__(self):
print("A.__init__.start")
print("A.__init__.end") class B(A):
def __init__(self):
print("B.__init__.start")
super(B, self).__init__()
print("B.__init__.end") class C(A):
def __init__(self):
print("B.__init__.start")
A.__init__(self)
print("B.__init__.end") b = B()
# B.__init__.start
# A.__init__.start
# A.__init__.end
# B.__init__.end c = C()
# B.__init__.start
# A.__init__.start
# A.__init__.end
# B.__init__.end
二:super方法只在新式类中适用
>>> class A:
... def __init__(self):
... print("A.__init__.start")
... print("A.__init__.end")
...
>>> class B:
... def __init__(self):
... print("B.__init__.start")
... super(B, self).__init__()
... print("B.__init__.end")
...
>>> class C(A):
... def __init__(self):
... print("B.__init__.start")
... A.__init__(self)
... print("B.__init__.end")
...
>>> b = B()
B.__init__.start
Traceback (most recent call last):
File "<stdin>", line , in <module>
File "<stdin>", line , in __init__
TypeError: must be type, not classobj
三:注意super()不是父类,而是执行MRO顺序中的下一个类!!
class E(object):
def __init__(self):
print("E") class D(object):
def __init__(self):
print("D")
super(D, self).__init__() class C(E):
def __init__(self):
print("C")
super(C, self).__init__() class B(D):
def __init__(self):
print("B")
super(B, self).__init__() class A(B,C):
def __init__(self):
print("A")
super(A, self).__init__() print(A.__mro__) #A->B->D->C->E
obj = A() #ABDCE
由最后输出可以知道,super是指向MRO顺序中自己类的下一个类。
def super(class_name, self):
mro = self.__class__.mro() #获取mro的列表
return mro[mro.index(class_name) + 1] #获取自己的索引号,去返回下一个类
四:super()可以避免重复调用
(一)__init__方法可能导致被执行多次
class A(object):
def __init__(self):
print("A.__init__") class B(A):
def __init__(self):
print("B.__init__")
A.__init__(self) class C(B,A):
def __init__(self):
print("C.__init__")
A.__init__(self)
B.__init__(self) c = C()
C.__init__
A.__init__
B.__init__
A.__init__ #出现重复调用
注意:
class C(A,B): #会因为无法创建MRO而出错
def __init__(self):
print("C.__init__")
A.__init__(self)
B.__init__(self) TypeError: Cannot create a consistent method resolution
order (MRO) for bases A, B
(二)使用super方法可以避免重复调用
class A(object):
def __init__(self):
print("A.__init__") class B(A):
def __init__(self):
print("B.__init__")
super(B, self).__init__() class C(B,A):
def __init__(self):
print("C.__init__")
super(C, self).__init__() c = C()
C.__init__
B.__init__
A.__init__
同样:
class C(A,B): #也是因为无法生成MRO顺序出错
def __init__(self):
print("C.__init__")
super(C, self).__init__() TypeError: Cannot create a consistent method resolution
order (MRO) for bases A, B
详细解决可以在推文:C3算法了解(2)中看到。下面也会写产生的原因(在生成MRO顺序时出错)
正确继承下的解法:

解法C3算法:

错误继承的原因:

C3算法解题:

推文:https://www.zhihu.com/question/20040039
python---方法解析顺序MRO(Method Resolution Order)<以及解决类中super方法>的更多相关文章
- 【转】python---方法解析顺序MRO(Method Resolution Order)<以及解决类中super方法>
[转]python---方法解析顺序MRO(Method Resolution Order)<以及解决类中super方法> MRO了解: 对于支持继承的编程语言来说,其方法(属性)可能定义 ...
- 转 -- Python: 多继承模式下 MRO(Method Resolution Order) 的计算方式关乎super
大家可能已经知道了,在 Python 3(Python 2 的新式类)中多继承模式是使用 C3 算法来确定 MRO(Method Resolution Order) 的. 那么具体是怎么计算的呢?本文 ...
- Python的程序结构[2] -> 类/Class[2] -> 方法解析顺序 MRO
方法解析顺序 / MRO (Method Resolution Order) 关于方法解析顺序(MRO)的详细内容可以参考文末链接,这里主要对 MRO 进行简要的总结说明以及一些练习示例. 经典类和新 ...
- sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO
sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO 今天在弄一个 sqlalchemy 的数据库基类的时候,遇到了跟多继承相关的一个小问题,因此顺便看了一 ...
- Python的方法解析顺序(MRO)[转]
本文转载自: http://hanjianwei.com/2013/07/25/python-mro/ 对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就 ...
- python 方法解析顺序 mro
一.概要: mor(Method Resolution Order),即方法解析顺序,是python中用于处理二义性问题的算法 二义性: 1.两个基类,A和B都定义了f()方法,c继承A和B那么C调用 ...
- Python的方法解析顺序(MRO)
mro即method resolution order,主要用于在多继承时判断调的属性的路径(来自于哪个类). http://blog.csdn.net/imzoer/article/details/ ...
- CodeChef - MRO Method Resolution Order(打表)
题意:有一种关系叫继承,那么继承父类的同时也会继承他的一个函数f,能继承任意多个父类或不继承,但不能继承自己的子类.现在规定一个列表,这个列表必须以1~N的顺序排列,并且父类不会排在子类后面,1含有一 ...
- Method Resolution Order – Python类的方法解析顺序
在支持多重继承的编程语言中,查找方法具体来自那个类时的基类搜索顺序通常被称为方法解析顺序(Method Resolution Order),简称MRO.(Python中查找其它属性也遵循同一规则.)对 ...
随机推荐
- 文献:Technology-related Disasters:A Survey toward Disaster-resilient Software Defined Networks
DISASTER的定义和影响(本文中) 定义范围: 自然灾害,比如洪水.地震等造成一定范围类的节点故障: 恶意攻击,DDOS攻击或者电磁脉冲攻击造成节点故障: 技术相关的问题,配置错误或者误操作等: ...
- beat冲刺(5/7)
目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:beta冲刺(5/7) 团队部分 后敬甲(组长) 过去两天完成了哪些任务 ppt制作中 数据集标注 接下来的计划 制作p ...
- 利用python进行简单的图像处理:包括打开,显示以及保存图像
利用python进行简单的图像处理:包括打开,显示以及保存图像 利用PIL处理 PIL(python image library) 是python用于图片处理的package.但目前这个package ...
- 【Coursera】因子分析模型
一.协方差矩阵 协方差矩阵为对称矩阵. 在高斯分布中,方差越大,数据分布越分散,方差越小发,数据分布越集中. 在协方差矩阵中,假设矩阵为二维,若第二维的方差大于第一维的方差,则在图像上的体现就是:高斯 ...
- Alpha版本冲刺(六)
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...
- JDBC连接数据库代码和步骤
JDBC连接数据库 创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序 在连接数据库之前,首先要加载想要连接的数据库的驱动,这通过java.lang.Class类的静态方法 ...
- 二级制包安装Tomcat 与 RPM包安装Tomcat
1:下载二级制包 wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-8/v8.0.47/bin/apache-tomcat-8.0.47.tar.g ...
- 交换机、linux光衰查询
RX收光,TX发光 一.交换机 命令: display interface transceiver brief 结果: ...... HW6851 10GE1/0/15 transceiver dia ...
- Python日记——nginx+Gunicorn部署你的Flask项目
转自:http://blog.csdn.net/qq_32198277/article/details/52432890 大家在学习Python的时候常常都是输入 python 文件名.py 这样 ...
- javascript定时保存表单数据的代码
(忘记是不是两家邮箱都有这个功能). 那这个功能是怎么做的呢? 定时,我们知道怎么弄,但保存呢?也许我们会通过隐藏域等手段来存放数据.但是,这个却有个缺点:那就是刷新页面后,数据将会丢失. 而此时,就 ...
