3

使用super()和直接使用父类名是否有区别?例如:super()和Parent类名有什么区别?

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)之间的差异?

+0

'super()'使用** MRO **解决呼叫... ... –

+0

仅当您的子类有多个超类时,或者您可能在某些时候将您的子类更改为继承一个不同的超类。顺便说一句,“父类”不是通常的继承术语。 – khelwood

+0

@khelwood:严格地说,这不是真的:如果你继承了一个具有多重继承的类,你的'super()'实际上可以委托给一个slibing,而不是父类。它只是返回'__mro__'中的下一行。 –

回答

6

不在这种情况下。但在一般情况,特别是当你使用多重继承super()委托给下一个对象在方法解析顺序(MRO)作为documentation指定:

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

返回一个代理对象将方法调用委托给父代或 si金光闪闪的类。这对访问在类中被覆盖的继承方法 非常有用。搜索顺序与getattr()使用的 相同,只是跳过了类型本身。

类型的__mro__属性列出了由两个getattr()super()所使用的方法的分辨率搜索顺序。属性 是动态的,只要继承层次更新为 ,就可以更改。

(...)

(复制,黑体字加)

例如说你定义类,如(从this question, where the MRO is discussed in more detail借用):

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__在于:

  • Asuper().__init__D.__init__;
  • super().__init__DB.__init__;
  • super().__init__BC.__init__;
  • super().__init__ of C is E.__init__;
  • super().__init__ of E is G.__init__;
  • super().__init__ of G is H.__init__;
  • super().__init__ of H is F.__init__;和
  • super().__init__Fobject.__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的背景下,认为:

  • super().__init__DE.__init__;
  • super().__init__ of E is G.__init__;
  • super().__init__ of G is H.__init__;
  • super().__init__ of H is F.__init__;和
  • super().__init__Fobject.__init__

所以这里Dsuper()导致E(为__init__不是在A背景相同。

+1

我想你错过了最重要的部分在那里结束你的最后一句太快了:'A中的super()'将委托给'D','D'中的'super()'调用委托给'B',而如果你用' D'实例的'super()'调用将转到'E'。 – Duncan

+0

@Duncan:完全没有,请参阅最新的答案。 –

+1

是的,您的编辑与我的评论交叉。虽然我仍然认为,对于直接D实例'super()'来说,它会有所不同, – Duncan

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

感知你不通过“自我” - 它会自动插入。

super()首次设计在Python 2至允许类被重用为一个类层次混入的方式,他们的直接超类可能会改变:

让我们在某个时间点supose你的代码是这样的:

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的情况下工作,从而破坏了多重继承的目的。

当您使用super()相反,Python的执行为希望在类的__mro__属性下一个父类中的方法搜索(MRO =方法解析顺序。__mro__是连接到每个Python类的具体属性)。 - 因此,如果在某个时间点D上面的类别不再继承B,则在C中的呼叫将自动重新路由至A

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

相关问题