京公网安备 11010802034615号
经营许可证编号:京B2-20210330
Python类的多重继承问题深入分析
首先得说明的是,Python的类分为经典类 和 新式类
经典类是python2.2之前的东西,但是在2.7还在兼容,但是在3之后的版本就只承认新式类了
新式类在python2.2之后的版本中都可以使用
经典类和新式类的区别在于:
经典类是默认没有派生自某个基类的,而新式类是默认派生自object这个基类的:
# new style
class A(obejct):pass
2.经典类在类多重继承的时候是采用从左到右深度优先原则匹配方法的..而新式类是采用C3算法(不同于广度优先)进行匹配的
3.经典类是没有__MRO__和instance.mro()调用的,而新式类是有的.
为什么不用经典类,要更换到新式类
因为在经典类中的多重继承会有些问题...可能导致在继承树中的方法查询绕过后面的父类:
d = D()
d.foo1()
按照经典类的查找顺序从左到右深度优先的规则,在访问d.foo1()的时候,D这个类是没有的..那么往上查找,先找到B,里面没有,深度优先,访问A,找到了foo1(),所以这时候调用的是A的foo1(),从而导致C重写的foo1()被绕过.
所以python引入了新式类的概念,每个基类都继承自object并且,他的匹配规则也从深度优先换到了C3
C3算法
C3算法是怎么做匹配的呢..在问答版块上面讨论之后,归结如下:
C3算法的一个核心是merge.
在merge列表中,如果第一个序列mro的第一个类是出现在其它序列,并且也是第一个,或者不出现其它序列,那么这个类就会从这些序列中删除,并合到访问顺序列表中
比如:(引用问题中zhuangzebo的回答@zhuangzebo)
首先需要知道 O(object)的mro(method resolution order)列表是[O,]
那么接下来是:
然后还有一种特殊情况:
比如:
merge(DO,CO,C) 先merge的是D
merge(DO,CO,C) 先merge的是C
意思就是.当出现有 一个类出现在两个序列的头(比如C) 这种情况和 这个类只有在一个序列的头(比如D) 这种情况同时出现的时候,按照顺序方式匹配。
新式类生成的访问序列被存储在一个叫MRO的只读列表中..
你可以使用instance.__MRO__或者instance.mro()来访问
最后匹配的时候就按照MRO序列的顺序去匹配了
C3和广度优先的区别:
举个例子就完全明白了:
按照广度优先遍历,F的MRO序列应该是[F,C,E,B,D,A]
但是C3是[F,E,D,C,B,A]
意思是你可以当做C3是在一条链路上深度遍历到和另外一条链路的交叉点,然后去深度遍历另外一条链路,最后遍历交叉点
新式类和经典类的super和按类名访问问题
在经典类中,你如果要访问父类的话,是用类名来访问的..
这样子看起来没三问题,但是如果类的继承结构比较复杂,会导致代码的可维护性很差..
所以新式类推出了super这个东西...
这时候,又有一个问题:当类是多重继承的时候,super访问的是哪一个类呢?
super实际上是通过__MRO__序列来确定访问哪一个类的...实际上就是调用__MRO__中此类后面的一个类的方法.
比如序列为[F,E,D,C,B,A]那么F中的super就是E,E的就是D
super和按照类名访问 混合使用带来的坑
class B(object):
def __init__(self):
print "enter B"
print "leave B"
class C(A):
def __init__(self):
print "enter C"
super(C, self).__init__()
print "leave C"
class D(A):
def __init__(self):
print "enter D"
super(D, self).__init__()
print "leave D"
class E(B, C):
def __init__(self):
print "enter E"
B.__init__(self)
C.__init__(self)
print "leave E"
class F(E, D):
def __init__(self):
print "enter F"
E.__init__(self)
D.__init__(self)
print "leave F"
这时候打印出来是:
可以看出来D和A的初始化函数被乱入了两次!
按类名访问就相当于C语言之前的GOTO语句...乱跳,然后再用super按顺序访问..就有问题了
所以建议就是要么一直用super,要么一直用按照类名访问
最佳实现:
避免多重继承
super使用一致
不要混用经典类和新式类
调用父类的时候注意检查类层次
以上便是本人对于python类的继承的认识了,希望对大家能有所帮助
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
平均数是数据分析、数理统计与日常运算中最基础、最常用的统计量,核心作用是浓缩一组数据的整体水平、刻画数据集中趋势。在众多 ...
2026-08-24在MySQL数据库中,InnoDB存储引擎作为主流事务型引擎,默认事务隔离级别为可重复读(Repeatable Read,RR),这与SQL Server、Or ...
2026-08-24 很多数据分析师拿到数据就开始清洗、建模,但当被问到“这批数据属于什么类型——结构化还是非结构化?分类变量还是数值变量 ...
2026-08-24 很多数据分析师画过趋势图、做过业绩预测,但当被问到“这个月销售额增长20%,到底是长期趋势自然增长,还是促销活动的短期 ...
2026-08-21在数据分析与数据可视化工作中,直方图是展示数据分布特征、离散程度、集中区间的核心图表,能够直观呈现数值数据的频次分布规律 ...
2026-08-20在数据分析领域有一句核心准则:垃圾数据进,垃圾数据出。数据清洗是数据分析、数据建模、数据可视化之前的必经前置工序,也是保 ...
2026-08-20 很多数据分析师做过按月份的销售额趋势图,画过按天的流量折线图,但当被问到“时间序列和普通数据有什么本质区别”“季节性 ...
2026-08-20在Python数据分析与数据清洗工作中,Pandas是最核心的数据处理库,DataFrame是结构化数据的标准存储格式。在实时数据采集、循环 ...
2026-08-19在零售行业大数据分析与精细化运营领域,纸尿裤旁摆放啤酒是最经典、最具代表性的商业案例。两种看似毫无关联的商品,一个是婴幼 ...
2026-08-19 很多数据分析师能熟练地计算指标、搭建标签体系,但当被问到“画像到底在解决什么问题”“画像和标签是什么关系”“画像如何 ...
2026-08-19在数据分析、业务监控、质量检测与风险管控工作中,数据波动性是衡量数据稳定性、业务健康度、结果可信度的核心依据。数据波动代 ...
2026-08-18很多分析师在设计标签时思路清晰,但真到落地环节却面临“数据在手,不知如何转化为可用标签”的困境:或因加工方式选择不当导致 ...
2026-08-18在数据分析、业务评价、产品评级、用户分层与综合决策场景中,单一指标往往无法全面、客观地评价事物整体水平。现实中的评价对象 ...
2026-08-18在数理统计、假设检验、数据分析与机器学习领域中,卡方分布(χ²分布)是继正态分布、t分布之后最重要的连续型概率分布之一。 ...
2026-08-17在Python数据清洗、文本校验、账号密码规则校验、脏数据过滤、字符串规整化处理中,正则表达式是最高效、最常用的文本匹配工具。 ...
2026-08-17 很多分析师每天和数据打交道,但当被问到“标签是什么”“标签和指标有什么区别”“标签体系如何设计”时,却常常答不上来。 ...
2026-08-17手游行业具备用户迭代快、竞争激烈、用户粘性易流失的典型特征。随着新游持续上线、玩家审美升级、玩法疲劳等问题出现,存量用户 ...
2026-08-14在数字化产品运营、商业数据分析、业务增长管理中,零散的指标统计无法支撑系统性的业务决策。单一的点击率、转化率、销量数据只 ...
2026-08-14 很多数据分析师每天都在写SQL,但当被问到“数据查询语言(DQL)的本质是什么”“SELECT语句中各子句的书写顺序与实际执行顺 ...
2026-08-14在数据库数据分析、数据清洗、报表统计与业务查询场景中,日期时间是最高频、最核心的基础字段。数据库中存储的日期格式多样,包 ...
2026-08-13