Python super()和直接调用超类的区别
在Python 2.7和3中,我使用以下方法调用超类的函数:Python super()和直接调用超类的区别,python,oop,python-2.7,python-3.x,superclass,Python,Oop,Python 2.7,Python 3.x,Superclass,在Python 2.7和3中,我使用以下方法调用超类的函数: class C(B): def __init__(self): B.__init__(self) 我发现也可以用super(B,self)替换B.。\uuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu 这样做有什么优点或缺点吗?至少对
class C(B):
def __init__(self):
B.__init__(self)
我发现也可以用super(B,self)替换B.。\uuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
这样做有什么优点或缺点吗?至少对我来说,直接从B
调用它更有意义,但可能有一个很好的理由,即super()
只能在使用元类时使用(我通常避免使用元类)。对于单继承,super()
只是引用基类型的一种更奇特的方式。这样,您可以使代码更易于维护,例如,如果您想更改基类型的名称。当您在任何地方都使用super
时,只需在class
行中对其进行更改
然而,多重继承带来了真正的好处。使用super
时,单个调用不仅会自动调用所有基类型的方法(按照正确的继承顺序),而且还会确保每个方法只调用一次
这本质上允许类型具有一个属性,例如,您有一个单一的基类型a
,以及两个类型B
和C
,它们都派生自a
。然后您有一个类型D
,它继承自B
和C
(使其隐式继承自a
两次)。如果现在显式地调用基类型的方法,那么最终将调用A的方法两次。但是使用super
,它只会调用它一次:
class A (object):
def __init__ (self):
super().__init__()
print('A')
class B (A):
def __init__ (self):
super().__init__()
print('B')
class C (A):
def __init__ (self):
super().__init__()
print('C')
class D (C, B):
def __init__ (self):
super().__init__()
print('D')
当我们现在实例化D
时,我们得到以下输出:
>>> D()
A
B
C
D
<__main__.D object at 0x000000000371DD30>
这是输出:
>>> D2()
A2
B2
A2
C2
D2
<__main__.D2 object at 0x0000000003734E48>
>>D2()
A2
地下二层
A2
C2
D2
如您所见,A2
出现两次。这通常不是你想要的。当您手动调用一个使用super
的基本类型的方法时,它会变得更加混乱。因此,您应该只使用super()
,以确保一切正常运行,并且不必太担心它。对于单继承,super()
只是引用基类型的一种更为奇特的方式。这样,您可以使代码更易于维护,例如,如果您想更改基类型的名称。当您在任何地方都使用super
时,只需在class
行中对其进行更改
然而,多重继承带来了真正的好处。使用super
时,单个调用不仅会自动调用所有基类型的方法(按照正确的继承顺序),而且还会确保每个方法只调用一次
这本质上允许类型具有一个属性,例如,您有一个单一的基类型a
,以及两个类型B
和C
,它们都派生自a
。然后您有一个类型D
,它继承自B
和C
(使其隐式继承自a
两次)。如果现在显式地调用基类型的方法,那么最终将调用A的方法两次。但是使用super
,它只会调用它一次:
class A (object):
def __init__ (self):
super().__init__()
print('A')
class B (A):
def __init__ (self):
super().__init__()
print('B')
class C (A):
def __init__ (self):
super().__init__()
print('C')
class D (C, B):
def __init__ (self):
super().__init__()
print('D')
当我们现在实例化D
时,我们得到以下输出:
>>> D()
A
B
C
D
<__main__.D object at 0x000000000371DD30>
这是输出:
>>> D2()
A2
B2
A2
C2
D2
<__main__.D2 object at 0x0000000003734E48>
>>D2()
A2
地下二层
A2
C2
D2
如您所见,A2
出现两次。这通常不是你想要的。当您手动调用一个使用super
的基本类型的方法时,它会变得更加混乱。因此,您应该只使用super()
来确保一切正常,并且不必太担心它。基本类型:?。基类、子类等:)似乎更多natural@MikeWilliamson你的理解部分正确。当调用super()
时,确定顺序的逻辑实际上不会被计算。顺序的基础是Python中的方法解析顺序(MRO),它基本上是类型层次结构的一致线性化。您可以通过查看D来查看D的MRO。基本上是D、C、B、A、object
。不幸的是,正确计算MRO有点复杂;它使用。但是简化了,你的“看”模型是有效的。@MikeWilliamsonsuper()
所做的不是计算下一步,而是简单地告诉Python在MRO中继续。这就是为什么所有属于层次结构的类都应该使用super()
,这也是a
调用super()
的原因。如果您要添加另一个类型类X(对象)
,并使D
也继承自该类型,那么您将看到,如果没有A
的super()
,将不会调用X
。由于在MRO中,X
位于A
之后,因此需要使用super()
命令Python在MRO中继续。@MikeWilliamson我不知道你的意思。。MRO是使用该算法计算的(这可能会变得非常复杂;请查看Wikipedia上的示例)。计算MRO后,super()
调用将按该顺序调用类型。当然,由于super()
是函数调用,因此之后它会以相反的顺序返回;但那只是调用堆栈。@Piyuskansal在类C
中,super()
做的事情与super(C,self)
做的事情相同。Python3引入了这个shorcut,您不需要为默认情况指定参数。在大多数情况下(大约99%),您只想使用super()
。通过向它传递不同的类型,例如super(ParentType,self)
,您将跳过MRO中的类型,因此这可能不是您想要做的。基本类型:?。基类、子类等:)似乎更多natural@MikeWilliamson你的理解部分正确。