Python中类的mro与继承关系详解(二)
目录
- 前言
- 多重继承
- 思考片刻
- 总结
前言
版本:
- windows 10.0
- python 3.8
多重继承
在Python数字比较与类结构中有简略提到类,且在Python中类的mro与继承关系详解稍有解释继承关系,用到一个基类Animal
如下:
class Animal: property_ = '能够思考' def __init__(self, name, age, value): self.name_ = name self.age_ = age self.val_ = val
再定义Action
活动作为另一个基类:
class Action: def __init__(self, action, val): self.action_ = action self.val_ = val
- 现在需定义一个
Dog
类,不仅是动物,还能够跑,可以来继承上面两个类来定义:
class Dog(Animal, Action): def __init__(self, name, age, action, val): Animal.__init__(self, name, age, val+1) Action.__init__(self, action, val) dog = Dog('大福', 8, '跑', 78) print(dog.__dict__) # {'name_': '大福', 'age_': 8, 'val_': 78, 'action_': '跑'}
发现打印出的实例属性,好像字典的键值更新,先初始化Animal时,val传入的值为79,而后被更新为78,这里为什么不能像继承单个类一样直接用super方法代替呢。
上一篇有提到mro解析顺序,可进行尝试,不重写__init__方法,发现Dog
类只能传入三个参数,且都为Animal
类的参数,因为继承的两个父类都有该方法,优先继承左边的父类方法,如果想都继承可以考虑这样的形式,然而会提高后续维护的困难性。
可以将最左边的父类改成super方式:
class Dog(Animal, Action): def __init__(self, name, age, action, val): super().__init__(name, age, val+1) Action.__init__(self, action, val)
mro解析顺序,与上面所述一致:
Dog.mro() # [__main__.Dog, __main__.Animal, __main__.Action, object]
- 祖孙类
如再进行继承,视Dog
为父类,其Animal
,Action
都为祖父类,定义一个Pet
类:
class Pet(Dog): pass pet = Pet('大福', 8, '跑', 78)
传入参数,和实例化的对象跟Dog
一样,如果需要改写某个方法,可以参照之前的方法进行改写,另外若在保留原方法的逻辑上进行补充则用super方法。
Pet
类的mro:
Pet.mro() # [__main__.Pet, __main__.Dog, __main__.Animal, __main__.Action, object]
思考片刻
通过上面的继承及对应的mro解析顺序,可以思考以下通过多重继承类后,输出的x属性值为多少:
class Alpha: def __init__(self, val): self.x = val class Beta(Alpha): pass class Gamma: def __init__(self, val): self.x = val + 1 class Omega(Gamma): def __init__(self, val): super().__init__(val + 1) class Kappa(Beta, Omega): pass k = Kappa(1) print(k.x)
如果脑内没有一个mro解析顺序图,这里准备了:
[__main__.Kappa, __main__.Beta, __main__.Alpha, __main__.Omega, __main__.Gamma, object]
这里或许会有疑问,Beta
后面不是Omega
吗?怎么到Alpha
了,可以先看下Omega
,继承Gamma
,而Gamma
跟Alpha
并不是同源的,类似于Dog
类的继承,那么优先就会使用Alpha
的__init__方法,所以在传入参数值1的时候,仅运行了Alpha
内的self.x = val,属性x被赋值成1,在最后print输出即为1,打印结果检查:
print(k.x) # 1
若把Gamma
类改成继承Alpha
类,再次猜测print(k.x)的值为多少?
class Alpha: def __init__(self, val): self.x = val class Beta(Alpha): pass class Gamma(Alpha): def __init__(self, val): self.x = val + 1 class Omega(Gamma): def __init__(self, val): super().__init__(val + 1) class Kappa(Beta, Omega): pass k = Kappa(1) print(k.x)
查看mro解析顺序:
[__main__.Kappa, __main__.Beta, __main__.Omega, __main__.Gamma, __main__.Alpha, object]
此时发现Alpha
解析优先级排在最后,Beta
跟Omega
可以看做是Beta
跟Gamma
的优先级比较,因为Omega
继承Gamma
,且重写了__init__方法,所以当传入参数时会对Gamma
类的属性进行赋值,虽然Beta
类直接继承Alpha
,但Gamma
类也直接继承,所以Alpha
解析顺序需要排在Gamma
后面,从而当Kappa
类传入参数时,经过Omega
的super加1,传入到Gamma处时为:self.x = val + 1中的val为2,输出的k.x的值即为3,查看打印结果:
print(k.x) # 3
总结
通过连续两篇对类继承及mro解析顺序的说明,理解类在多重继承中的变化,无论继承多少遍,总归要回归本心,但也不能胡乱继承,有条理的,有意义的继承,才能让自己乃至他人更好理解当下写出的类。
到此这篇关于Python中类的mro与继承关系详解的文章就介绍到这了,更多相关Python mro内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!