调用父类方法
super()
- 为了调用父类(超类)的一个方法,可以使用
super()函数
1 | class A: |
super()函数的一个常见用法是在__init__()方法中确保父类被正确的初始化了1
2
3
4
5
6
7
8
9
10
11class A:
def __init__(self):
self.x = 0
class B(A):
def __init__(self):
super().__init__()
self.y = 1
b = B()
print(b.x,b.y) # 0,1
使用dataclasses改写1
2
3
4
5
6
7
8
9
10
11
12from dataclasses import dataclass
@dataclass
class A:
x:int = 0
@dataclass
class B(A):
y:int = 1
b = B()
print(b) # B(x=0, y=1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class Father:
def __init__(self, name):
self.name = name
print("init Father's name")
class Mather:
def __init__(self, age):
self.age = age
print("init Mather's age")
class Son(Father, Mather):
def __init__(self, name, age, sex):
super().__init__(name) # 先继承 Father 的 name
super(Father, self).__init__(age) # 继承后 再继承 Mother 的age
self.sex = sex # 最后 实例化自己的 sex
print("init Son's sex")
if __name__ == "__main__":
son = Son("Tom", 5, "Male")
print(Son.__mro__) # (<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Mather'>, <class 'object'>)
print(son.name, son.age, son.sex)
1 | from dataclasses import dataclass |
MRO列表
Python会在MRO列表上继续搜索下一个类。
只要每个重定义的方法统一使用 super() 并只调用它一次,
那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次
super()有个令人吃惊的地方是它并不一定去查找某个类在MRO中下一个直接父类,
你甚至可以在一个没有直接父类的类中使用它
1 | class A: |
1 | class C(B,A): |
关于super()
由于 super() 可能会调用不是你想要的方法,你应该遵循一些通用原则。
首先,确保在继承体系中所有相同名字的方法拥有可兼容的参数签名(比如相同的参数个数和参数名称)。
这样可以确保 super() 调用一个非直接父类方法时不会出错。
其次,最好确保最顶层的类提供了这个方法的实现,这样的话在MRO上面的查找链肯定可以找到某个确定的方法。
在Python社区中对于 super() 的使用有时候会引来一些争议。
尽管如此,如果一切顺利的话,你应该在你最新代码中使用它。
Raymond Hettinger为此写了一篇非常好的文章
Python’s super() Considered Super
通过大量的例子向我们解释了为什么 super() 是极好的。