super()和Parent类名之间有什么区别?

cod*_*ash 13 python inheritance initialization super method-resolution-order

super()直接使用和使用父类名称有区别吗?例如:

class Parent:
    def __init__(self):
        print("In parent")
        self.__a=10

class Child(Parent):
    def __init__(self):
        super().__init__()     # using super()
        Parent.__init__(self)  # using Parent class name

c=Child()
Run Code Online (Sandbox Code Playgroud)

是否有内部之间的差异super().__init__()Parent.__init__(self)

Wil*_*sem 9

不是在这种情况下.但总的来说,尤其是当您使用多重继承时,请按照文档中的规定super()委托方法解析顺序(MRO)中的下一个对象:

super([type[, object-or-type]])

返回将方法调用委托给父类或兄弟类类型的代理对象.这对于访问已在类中重写的继承方法很有用.getattr()除了跳过类型本身之外,搜索顺序与使用的搜索顺序相同.

__mro__类型的属性列出的方法解析搜索顺序双方使用getattr()super().该属性是动态的,并且可以在更新继承层次结构时更改.

(......)

(复制,粗体添加)

比如说你定义了类(从这个问题中借用,更详细地讨论了MRO):

class F:
    def __init__(self):
        print('F%s'%super().__init__)
        super().__init__()

class G: 
    def __init__(self):
        print('G%s'%super().__init__)
        super().__init__() 

class H: 
    def __init__(self):
        print('H%s'%super().__init__)
        super().__init__()

class E(G,H):
    def __init__(self):
        print('E%s'%super().__init__)
        super().__init__()

class D(E,F): 
    def __init__(self):
        print('D%s'%super().__init__)
        super().__init__() 

class C(E,G): 
    def __init__(self):
        print('C%s'%super().__init__)
        super().__init__()

class B(C,H): 
    def __init__(self):
        print('B%s'%super().__init__)
        super().__init__()

class A(D,B,E): 
    def __init__(self):
        print('A%s'%super().__init__)
        super().__init__()
Run Code Online (Sandbox Code Playgroud)

接着__mro__A是:

A.__mro__ == (A,D,B,C,E,G,H,F,object)
Run Code Online (Sandbox Code Playgroud)

现在,如果我们打电话A(),它打印:

A<bound method D.__init__ of <__main__.A object at 0x7efefd8645c0>>
D<bound method B.__init__ of <__main__.A object at 0x7efefd8645c0>>
B<bound method C.__init__ of <__main__.A object at 0x7efefd8645c0>>
C<bound method E.__init__ of <__main__.A object at 0x7efefd8645c0>>
E<bound method G.__init__ of <__main__.A object at 0x7efefd8645c0>>
G<bound method H.__init__ of <__main__.A object at 0x7efefd8645c0>>
H<bound method F.__init__ of <__main__.A object at 0x7efefd8645c0>>
F<method-wrapper '__init__' of A object at 0x7efefd8645c0>
<__main__.A object at 0x7efefd8645c0>
Run Code Online (Sandbox Code Playgroud)

所以这意味着A尝试获取__init__的上下文中:

  • super().__init__AD.__init__;
  • super().__init__DB.__init__;
  • super().__init__BC.__init__;
  • super().__init__CE.__init__;
  • super().__init__EG.__init__;
  • super().__init__GH.__init__;
  • super().__init__HF.__init__; 和
  • super().__init__Fobject.__init__.

因此请注意,super()本身并不代表父母.例如super(),Dis BBis不是超类D,所以它实际上取决于对象的类型(不在类上).

现在,如果是D,那__mro__就是:

D.__mro__ = (D,E,G,H,F,object)
Run Code Online (Sandbox Code Playgroud)

如果我们构建一个,D我们得到:

D<bound method E.__init__ of <__main__.D object at 0x7efefd864630>>
E<bound method G.__init__ of <__main__.D object at 0x7efefd864630>>
G<bound method H.__init__ of <__main__.D object at 0x7efefd864630>>
H<bound method F.__init__ of <__main__.D object at 0x7efefd864630>>
F<method-wrapper '__init__' of D object at 0x7efefd864630>
Run Code Online (Sandbox Code Playgroud)

所以D的背景下认为:

  • super().__init__DE.__init__;
  • super().__init__EG.__init__;
  • super().__init__GH.__init__;
  • super().__init__HF.__init__; 和
  • super().__init__Fobject.__init__.

因此,这里super()D导致E(对于__init__)这是不是在上下文中的相同A.

  • @Duncan:这确实是一个好主意.更新了它. (2认同)

jsb*_*eno 7

super().__init__(*args, **kwargs)   
Run Code Online (Sandbox Code Playgroud)

感觉你没有传递“自我”——它是自动插入的。

super()最初是在 Python 2 中设计的,允许类在类层次结构中作为 mixins 重用,其直接超类可能会发生变化:

假设在某个时间点您的代码如下:

class A: pass
class B(A): 
    def __init__(self, *args, **kwargs):
          ...
          # Fixed call to A
          A.__init__(self, *args, **kwargs)

class C(A):
    def __init__(self, *args, **kwargs):
          ...
          # Fixed call to A
          A.__init__(self, *args, **kwargs)

class D(C, B): 
    pass
Run Code Online (Sandbox Code Playgroud)

此时,应该执行正确的 OOP 代码,C.__init__ 该代码应该将调用链接到B.__init__: 但当超类名称被硬编码时,不会发生 -A总是__init__接下来。如果您B.__init__在 中进行硬编码C,那么您将C无法在没有 的情况下工作B,从而违背了多重继承的目的。

当您使用super()替代方法时,Python 会根据类的属性执行下一个父类的方法搜索__mro__(mro = 方法解析顺序。__mro__是附加到每个 Python 类的具体属性)。- 因此,如果在某个时间点D上面的类不再继承自,则对 inB的调用将自动重新直接路由到。super().__init__CA

还值得注意的是,在 Python 3 中引入了无参数形式super来简化其使用 - 在此之前,必须硬编码对自己的类的引用并插入self参数。这种形式是 Python 中为数不多的在编译器本身中硬编码的例外之一 - 当在方法体中看到super(或) 时,它确实会在方法内部更改内容(即,它创建一个指向调用该类本身的变量)用途)__class____class__super