super() 和父类名有什么区别?



使用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__时:

  • Asuper().__init__D.__init__;
  • Dsuper().__init__B.__init__;
  • Bsuper().__init__C.__init__;
  • Csuper().__init__E.__init__;
  • Esuper().__init__G.__init__;
  • Gsuper().__init__H.__init__;
  • Hsuper().__init__F.__init__;和
  • Fsuper().__init__object.__init__.

因此请注意,super()本身并不委托给父级。例如,Dsuper()B的,而B不是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的背景下,它认为:

  • Dsuper().__init__E.__init__;
  • Esuper().__init__G.__init__;
  • Gsuper().__init__H.__init__;
  • Hsuper().__init__F.__init__;和
  • Fsuper().__init__object.__init__.

所以这里Dsuper()导致E(对于__init__),这在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__总是下一个。 如果你用CB.__init__进行硬编码,你会阻止C在没有B的情况下工作,从而破坏多重继承的目的。

当你改用super()时,Python 会根据类的__mro__属性(mro = 方法解析顺序。__mro__是附加到每个 Python 类的具体属性)。 - 因此,如果在某个时间点,上面的类D不再继承B,则对super().__init__的调用将直接C自动重新路由到A

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

相关内容

  • 没有找到相关文章

最新更新