python super()函数的详解
python是一门面向对象的语言,定义类时经常要用到继承,在类的继承中,子类继承父类中已经封装好的方法,不需要再次编写,如果子类如果重新定义了父类的某一方法,那么该方法就会覆盖父类的同名方法,但是有时我们希望子类保持父类方法的基础上进行扩展,而不是直接覆盖,就需要先调用父类的方法,然后再进行功能的扩展,这时就可以通过super来实现对父类方法的调用。
super的用法
看下面一个例子:
class a: def func(self): print("a的func执行") class b(a): def func(self): super().func() print("b扩展的func执行") b = b() b.func()
# 输出结果为:
# a的func执行
# b扩展的func执行
上面程序中,a是父类,b是a的子类,我们在a类中重定义了func()方法,在b类中重新定义了func()方法,在方法中通过super().func()又调用了父类的方法,所以执行结果才会有a类func()方法输出。
如果经常看python内置库及第三方库源码的话,你会发现,super用的非常多的地方是在子类中调用父类的初始化__init__()方法,这种用法非常常见。
class a: def __init__(self, x): self.x = x class b(a): def __init__(self, x, y): super().__init__(x) self.y = y b = b(1, 2) print(b.x, b.y)
看到这,你会想到super就是用来获取父类并用来调用父类方法的,这样说对不对呢,其实是不对的,使用supper获取的不是父类,而是mro列表中的下一个类,所谓mro列表即方法解析顺序(method resolution order)列表,它代表着类继承的顺序,我们可以使用以下几种获得某个类的mro列表:
c.mro() c.__mro__ c.__class__.__mro__
mro列表的顺序确定经历了很多次的变迁,最新的是通过c3线性化算法来实现的,感兴趣的话可以自行了解一下,总的来说,一个类的mro列表就是合并所有父类的mro列表,并遵循以下三条原则:
- 子类永远在父类前面
- 如果有多个父类,会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
下面来看一下下面这个例子:
class a(base): def func(self): print("a的func执行") super().func() print("a的func执行完毕") class b(base): def func(self): print("b的func执行") super().func() print("b的func执行完毕") class c(a, b): def func(self): print("c的func执行") super().func() print("c的func执行完毕") c = c() c.func() # 获取mro列表 print(c.__class__.__mro__)
执行结果如下:
上述程序中,base是父类,a、b都继承自base,c继承自 a、b,它们的继承关系就是一个典型的菱形继承,如下:
通过结果我们可以看出,super并不是获取父类并用来调用父类的方法,而是根据mro列表一次调用下一个类,使用c.__class__.__mro__可以获取mro列表,mro列表的顺序是c、a、b、base、object。
super的原理
super计算方法解析顺序中的下一个类,可以接收两个参数:
def super(cls, inst): mro = inst.__class__.mro() return mro[mro.index(cls) + 1]
总结
现在我们知道:supper获取的是mro列表中的下一个类,当前类的父类没有实质性的关系;还有如何查看mro列表。最后需要注意的是super以及mro列表,针对都是python新式类!
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!