Python mro
宿者朽命 人气:0前言
版本:
- 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解析顺序的说明,理解类在多重继承中的变化,无论继承多少遍,总归要回归本心,但也不能胡乱继承,有条理的,有意义的继承,才能让自己乃至他人更好理解当下写出的类。
加载全部内容