繁体   English   中英

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

[英]What's the difference between super() and Parent class name?

使用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()

内部是否有super().__init__()Parent.__init__(self)之间的区别?

不是在这种情况下 总的来说 ,尤其是当您使用多重继承时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__()

然后A__mro__是:

A.__mro__ == (A,D,B,C,E,G,H,F,object)

现在如果我们调用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>

所以这意味着A的上下文中 ,当试图获得__init__

  • super().__init__AD.__init__ ;
  • D super().__init__B.__init__ ;
  • B super().__init__C.__init__ ;
  • C super().__init__E.__init__ ;
  • E super().__init__G.__init__ ;
  • G super().__init__H.__init__ ;
  • H super().__init__F.__init__ ;
  • F super().__init__object.__init__

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

现在在D情况下, __mro__是:

D.__mro__ = (D,E,G,H,F,object)

如果我们构建一个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>

因此,在D的背景下,它认为:

  • D super().__init__E.__init__ ;
  • E super().__init__G.__init__ ;
  • G super().__init__H.__init__ ;
  • H super().__init__F.__init__ ;
  • F super().__init__object.__init__

所以这里Dsuper()导致E (对于__init__ ,这A的上下文中不一样A

super().__init__(*args, **kwargs)   

感觉你没有通过“自我” - 它会自动插入。

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

让我们在某个时间点使用您的代码:

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

在这一点上,正确的OOP代码应该执行C.__init__ ,它应该将调用链接到B.__init__ :但是当超类名称被硬编码时不会发生 - A__init__总是接下来。 如果你在C硬编码B.__init__ ,你会阻止C在没有B情况下工作,从而B.__init__多重继承的目的。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM