说明
一些Python入门书并没有讲清楚super()函数应该怎么用,只在说继承知识点的时候顺便一笔带过。为此我糊涂了好久、好久……
继承
Python中的继承很容易实现,如下:
class A(object):
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print("I'm A")
def show(self):
string = ("My name is {name}.\n"
"I'm {age}.".format(name=self.name, age=self.age))
print(string)
class B(A):
pass
if __name__ == "__main__":
b = B("Guan", 18)
b.greet()
b.show()
# 输出:
I'm A
My name is Guan.
I'm 18.
所以继承父类的时候,super()函数并非必要。
那什么时候确切的要用到super()呢?
答:欲求不满时。
使用super()
之所以需要“继承”,大部分原因是我们想要扩展基础类——需要派生类有更多的功能。当然了,如果只是额外增加一个“独立”功能,仍然用不到super()。如下:
class A(object):
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print("I'm A")
def show(self):
string = ("My name is {name}.\n"
"I'm {age}.".format(name=self.name, age=self.age))
print(string)
class B(A):
# “独立”功能
def cry(self):
print("cry ...")
if __name__ == "__main__":
b = B("Guan", 18)
b.cry()
# 输出:
cry ...
B类中的cry()是一个与A类完全无关的函数,所以直接定义就OK。但此时需求变了,我们需要B类的对象可以在自我介绍的时候先说hello。我们当然可以用如下方式重载show():
class B(A):
def show(self):
print("ya~hello~")
string = ("My name is {name}.\n"
"I'm {age}.".format(name=self.name, age=self.age))
print(string)
可这样做重复了A中的部分代码,很不“程序员”。所以super()出场了:
class B(A):
def show(self):
print("ya~hello~")
super().show()
但python2中需要这样写:
class B(A):
def show(self):
print("ya~hello~")
super(B, self).show() # 需要传入自己的类名以及对象self
乍一看super()的意思是:获取父类。而super().show()
就是调用父类的show()函数。是,也不是。
真实的super()
super()获取的是MRO列表中下一个类。什么是MRO呢?这里不是重点,它有自己计算的方式,有兴趣可以自己找找资料。
示例:
class A(object):
pass
class B(A):
pass
if __name__ == "__main__":
print(B.mro())
输出内容如下:[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
在MRO列表中,B的下一个类是A。所以在B类中的super(),代表A。这里刚好A是B的父类。也有不刚好的时候。
class A(object):
def __init__(self):
print("A")
super().__init__()
class B(A):
def __init__(self):
print("B")
super().__init__()
class C(A):
def __init__(self):
print("C")
super().__init__()
class D(B, C):
def __init__(self):
print("D")
super().__init__()
if __name__ == "__main__":
d = D()
print(D.mro())
# 输出:
D
B
C
A
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
注意ABCD的输出顺序。可以看到,B中调用super().__init__()
,没有打印“A”,而是“C”,这是符合MRO列表顺序的。
总结
- super()与父类没有直接关系
- super()获取的是MRO列表中下一个类
感谢
参考个人博客 FunHacks
https://funhacks.net/explore-python/Class/super.html
参考慕课老师 bobby
https://www.bilibili.com/video/av28281876/?p=22
还不快抢沙发