函数参考
以下内容引用自官方手册
返回一个代理对象,其可以用委派的方法调用类型的父系或兄弟类,这对于访问继承的方法(已经被重写的方法)很有用,检索顺序与使用getattr()相同。
类型的__mro__属性列出了getattr()和super()所用的方法解析检索顺序,该属性是动态的,并且无论何时更新继承层次都会改变。
如果第二个参数缺省,super对象的返回是未被绑定的;如果第二个参数是一个对象,则isinstance(obj, type)必须是True;如果第二个参数是一个类型(type),则issubclass(type2, type)必须是True(这对于类方法很有用)。
super有两种常规使用情形:
- 在类层次中的单个继承,super可用于引用父类,而不用明确命名它们,因此使得代码更具可维护性。这种使用与其他编程语言中的super相较很接近。
- 第二种使用情形,支持在动态执行环境中协同多重继承,这种用法是Python独创的,在静态编译语言或只支持单继承语言中还没见过。在那些需要用多重基类实现相同方法地方,super方法使得实现“钻石图”(“diamond diagrams”)成为可能。一个好的设计规范要求这种方法在各种情况下具有相同的调用标识,因为运行时决定调用的顺序,而调用顺序要适应类层次的修改,且调用顺序可以包含运行时之前未知的同级类。
对于两种使用情况,常规的superclass调用可以像这样:
class C(B):
def method(self, arg):
super().method(arg) # 这与下面的相同:
# super(C, self).method(arg)
注意:对于显式加点属性查找,super()可以作为绑定进程的一部分执行,例如super().__getitem__(name),为搜索类(支持协同多重继承)在可预测顺序内实现它自己的__getattribute__()方法。因此,对于使用声明或运算符(例如super()[name])的显式查找,super()是未定义的。
同样需要注意,除了0参数形式之外,super()不限制使用内部方法。两个参数形式明确指定了参数,且做出了合适的引用。0参数形式只能在类定义内部工作,其作为编译器而填入了必要的细节,确保可以正确的检索定义的类,同样可以也为普通方法访问当前实例。
实践使用指南
以下内容来自官方手册推荐的一篇博文 — 《Python’s super() considered super!》,部分Python 2的内容未摘录。
如果你没被Python内建的super()惊艳到,有可能是你还没有真正了解它的能力,又或者你还不知道如何有效的使用它。
已经写了关于super()的文章,但大多数都失败了,而这篇文章则试图通过以下几点改善这种状况:
- 提供实际使用案例
- 给出一个清楚的构思模型来阐明它是如何工作的
- 展示每次让可以它投入运行的谍报
- 使用super()创建类的具体建议
- 有帮助的真实举例:抽象ABCD钻石图
基础
使用Python 3语法,让我们从基础使用案例开始,为一个内建类的子类扩展方法:
class LoggingDict(dict):
def __setitem__(self, key, value):
logging.info('Settingto %r' % (key, value))
super().__setitem__(key, value)
这个类拥有它的父类(dict)同样的能力,但是它扩展了__setitem__方法,使得无论何时更新key都记录日志,在记录日志后,方法使用super()对实际上用key/value对更新字典的工作进行委派。
在引入super()前,我们可以用dict.setitem(self, key, value)硬链接调用。无论如何,super()更好,因为它是一个计算的间接引用。
间接引用的好处之一是我们不必通过名字指定委派类,如果你编辑资源代码将基础类切换为