MRO:Method Resolution Order
类的属性和实例的属性的关系:
如果现在有一个类A,他有一个属性name:
现在把他实例化:
image.png
打印这个实例的name:
image.png
现在用
__init__
初始化实例的变量:image.png
再打印实例a的属性name:
image.png
name的查找顺序是由下至上的,先查找实例的属性name,如果找不到,再查找类的属性name。
在多继承的情况下,这个顺序就会变得复杂。
如果基础关系是这样的:
那么如果搜索顺序是先搜索B——>D——>C——>E那么会出现一个问题就是:
如果D和C有重名的方法,如果按照这个顺序搜索,C中的方法可能永远也使用不到。
可以通过一种方法来查看实际的运行顺序是
__mro__
:image.png
python3后如果类不继承任何类,那么它默认继承object类。
如果基础关系是这样的:
那么如果搜索顺序是先搜索B——>D——>C那么会出现一个问题就是:
如果C中重写了D的方法,如果按照这个顺序搜索,C中的方法也可能永远也使用不到。
查看实际的运行顺序
__mro__
:image.png
从python2.3之后,python的属性搜索算法统一为一个算法叫C3算法,C3算法保证了以后每一个父类只会被调用一次。
具体实现见维基百科:
https://zh.wikipedia.org/wiki/C3%E7%BA%BF%E6%80%A7%E5%8C%96
所以如果现在有一个Parent类,一个Son1类继承自Parent,一个Son2类继承自Parent,再有一个Grandson继承自Son1和Son2,,如果想要不重复调用Parent中的方法,可以用super()
class Parent(object):
def __init__(self, name, *args, **kwargs):
print('Parent1')
self.name = name
print('Parent2')
class Son1(Parent):
def __init__(self, name, age,*args, **kwargs):
print("***Son1***")
self.age = age
super().__init__(name, *args, **kwargs)
print("***Son1***")
class Son2(Parent):
def __init__(self, name, gender,*args, **kwargs):
print("***Son2***")
self.gender = gender
super().__init__(name, *args, **kwargs)
print("***Son2***")
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
print("Grandson")
super().__init__(name, age, gender)
print("Grandson")
print(Grandson.__mro__ )
运行程序:
D:\>python test08.py
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
这个打印的结果就是C3算法的结果,它表示这个Grandson调用父类方法的顺序,也就是super到__mro__
里面去匹配,匹配到当前的类名,然后调用它的下一个类里的方法。
如果当前把Grandson实例化,可以看到打印顺序:
g1 = Grandson("haha", 12, "male")
运行:
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson
***Son1***
***Son2***
Parent1
Parent2
***Son2***
***Son1***
Grandson
super还有参数可以传递:
super(Grandson, self).__init__(name, age, gender)
当没有参数的时候,默认去mro中匹配的是当前的类名,有参数就去匹配给定的参数。
如果当前Grandson中的super传递参数如下:
super(Grandson, self).__init__(name, age, gender)
运行结果:
D:\>python test08.py
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson
***Son1***
***Son2***
Parent1
Parent2
***Son2***
***Son1***
Grandson
如果当前Grandson中的super传递参数如下:
super(Son2, self).__init__(name, age, gender)
运行结果:
D:\>python test08.py
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson
Parent1
Parent2
Grandson
而此时传递的参数就要注意了,父类需要的参数要传递过去。
网友评论