“超级”在Python中做什么?

有什么区别:

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

和:

class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

我已经看到只有单一继承才能在类中使用super类。 我可以看到为什么你会在多重继承中使用它,但我不清楚在这种情况下使用它的优点。


super()在单一继承中的好处是最小的 - 大多数情况下,您不必将基类的名称硬编码到使用其父方法的每个方法中。

但是,如果没有super() ,使用多重继承几乎是不可能的。 这包括像mixin,接口,抽象类等常见的习惯用法。这扩展到后来扩展你的代码。 如果有人后来想写一个扩展Child和mixin的类,他们的代码将无法正常工作。


有什么不同?

SomeBaseClass.__init__(self) 

意味着调用SomeBaseClass__init__ 。 而

super(Child, self).__init__()

意味着从实例的方法解析顺序中的Child __init__的父类调用绑定的__init__

如果实例是Child的一个子类,那么在方法解析顺序中可能会有一个不同的父类。

Python 2与3

这适用于Python 2和3:

super(Child, self).__init__()

这只适用于Python 3:

super().__init__()

它通过在堆栈框架中移动并获取方法的第一个参数(通常为实例方法的self或类方法的cls - 但可以是其他名称)以及找到类中的类(例如Child )自由变量(它在名称__class__作为方法中的自由闭包变量)。

我更喜欢演示使用super的交叉兼容方式,但如果您只使用Python 3,则可以不带参数地调用它。

具有向前兼容性的间接方向

它给你什么? 对于单一继承,从静态分析的角度来看,这个问题的例子实际上是相同的。 但是,使用super会为您提供一个具有向前兼容性的间接层。

向前兼容对于经验丰富的开发人员非常重要。 你希望你的代码在你改变它的时候保持最小的变化。 当你看看你的修订历史时,你想看看什么时候改变。

你可以从单一的继承开始,但是如果你决定添加另一个基类,你只需要改变这个基础 - 如果基类在你继承的类中改变(比如添加了一个mixin),你就会改变这课没有什么。 特别是在Python 2中,将参数设置为超级以及正确的方法参数是很困难的。 如果你知道你正在使用super单继承,这使得调试更加困难。

依赖注入

其他人可以使用您的代码并将父项注入方法解析中:

class SomeBaseClass(object):
    def __init__(self):
        print('SomeBaseClass.__init__(self) called')

class UnsuperChild(SomeBaseClass):
    def __init__(self):
        print('UnsuperChild.__init__(self) called')
        SomeBaseClass.__init__(self)

class SuperChild(SomeBaseClass):
    def __init__(self):
        print('SuperChild.__init__(self) called')
        super(SuperChild, self).__init__()

假设你为你的对象添加了另一个类,并且希望在Foo和Bar之间插入一个类(用于测试或其他原因):

class InjectMe(SomeBaseClass):
    def __init__(self):
        print('InjectMe.__init__(self) called')
        super(InjectMe, self).__init__()

class UnsuperInjector(UnsuperChild, InjectMe): pass

class SuperInjector(SuperChild, InjectMe): pass

使用un-super子程序无法注入依赖项,因为您正在使用的子项对要调用的方法进行了硬编码:

>>> o = UnsuperInjector()
UnsuperChild.__init__(self) called
SomeBaseClass.__init__(self) called

但是,具有使用super的孩子的类可以正确地注入依赖项:

>>> o2 = SuperInjector()
SuperChild.__init__(self) called
InjectMe.__init__(self) called
SomeBaseClass.__init__(self) called

结论

始终使用super引用父类。

你打算引用下一个在线的父类,而不是专门看到孩子继承的父类。

不使用super可以给你的代码的用户带来不必要的限制。


这并不是所有这些都假设基类是一种新式类?

class A:
    def __init__(self):
        print("A.__init__()")

class B(A):
    def __init__(self):
        print("B.__init__()")
        super(B, self).__init__()

在Python 2中不起作用。 class A必须是新样式的,即: class A(object)

链接地址: http://www.djcxy.com/p/5091.html

上一篇: What does 'super' do in Python?

下一篇: CSS: Setting width/height as Percentage minus pixels