问题历史:
super()函数的出现是为了简化继承的工作。在它出现之前,调用父类方法时必须显式指定父类的名称,这使得混合和多重继承变得不方便,并可能导致错误。super()会考虑继承顺序(MRO)。
问题:
在多重继承中,直接调用父类通常只会调用其方法,而忽略其他前辈。这打破了调用链。super()的任务是正确构建方法链,以考虑层次结构。
解决方案:
super()返回一个代理对象,该对象将调用委托给MRO中的下一个类。这允许统一地调用所有前辈的方法。
代码示例:
class A: def show(self): print("A.show()") class B(A): def show(self): print("B.show() -> ", end="") super().show() class C(A): def show(self): print("C.show() -> ", end="") super().show() class D(B, C): def show(self): print("D.show() -> ", end="") super().show() d = D() d.show() # 输出: D.show() -> B.show() -> C.show() -> A.show()
关键特点:
可以在静态方法中不带参数使用super吗?
不可以,在静态方法中没有self或cls。super()期望它在实例或类的方法中调用,其中有关于对象类型的信息。
如果在super()的调用链中跳过了父类方法,它会被调用吗?
不会。如果在链中没有调用super(),执行不会“传递”下去。因此,在重写方法时,始终要记住super(),否则部分前辈的逻辑将被跳过。
可以将任意参数传递给super()吗?
可以,但在Python 3中,不带参数的super()调用可以避免错误并且看起来更干净。传递参数仅在少数情况下是必要的(例如,与Python 2的兼容性),通常是不需要的。
优点:
负面案例:在一个大型项目中,父类的初始化包含了初始化,但一个子类忘记调用super().init()。结果出现了部分初始化的对象,属性未初始化。
优点:不需要手动调用每个父类。 缺点:如果有人跳过了super(),难以跟踪。
积极案例:合理实现的super()链确保了所有基类的正确初始化,简化了架构的维护和发展。
优点:代码的整洁,扩展的简单。 缺点:在复杂的MRO中容易出错——需要理解调用顺序。