文章目录
This question already has an answer here:
我试图理解super()的用法。从外观上看,这两个子类都可以创建,就好了。
我很想知道以下两个子类的实际区别。
class Base(object):
def __init__(self):
print "Base created"
class ChildA(Base):
def __init__(self):
Base.__init__(self)
class ChildB(Base):
def __init__(self):
super(ChildB, self).__init__()
ChildA()
ChildB()
super()`可以避免显式地引用基类,这可以很好。但主要优势来自多重继承,其中各种有趣的东西可以发生。如果还没有,请参阅super上的标准文档。 p>
请注意,Python
3.0中的语法已更改:您可以说super().__ init __(),而不是super(ChildB,self).__ init __() IMO更好一些。
I’m trying to understand super()
我们使用super的原因是,可能使用协作多重继承的子类将在方法解析顺序(MRO)中调用正确的下一个父类函数。
在Python 3中,我们可以这样调用它:
class ChildB(Base):
def __init__(self):
super().__init__()
在Python 2中,我们需要像这样使用它:
super(ChildB, self).__init__()
没有超级,你在使用多继承方面的能力有限:
Base.__init__(self) # Avoid this.
我在下面进一步解释。
“What difference is there actually in this code?:”
class ChildA(Base):
def __init__(self):
Base.__init__(self)
class ChildB(Base):
def __init__(self):
super(ChildB, self).__init__()
# super().__init__() # you can call super like this in Python 3!
这个代码的主要区别在于你在 init 中用 super 得到一个间接层,它使用当前类来确定下一个类的 init
`在MRO中查找。
If Python didn’t have super
这里的代码实际上与super非常相似(它是如何在C中实现的,减去一些检查和回退行为,并转换为Python):
class ChildB(Base):
def __init__(self):
mro = type(self).mro() # Get the Method Resolution Order.
check_next = mro.index(ChildB) + 1 # Start looking after *this* class.
while check_next < len(mro):
next_class = mro[check_next]
if '__init__' in next_class.__dict__:
next_class.__init__(self)
break
check_next += 1
写得更像本机Python:
class ChildB(Base):
def __init__(self):
mro = type(self).mro()
for next_class in mro[mro.index(ChildB) + 1:]: # slice to end
if hasattr(next_class, '__init__'):
next_class.__init__(self)
break
如果我们没有super对象,我们必须在每个地方编写这个手册代码(或者重新创建它!),以确保我们调用方法解析顺序!
super如何在Python 3中完成这个工作,而不需要明确地告诉它被调用的方法是哪个类和实例呢?
它获取调用堆栈框架,并找到该类(隐式存储为本地自由变量,使调用函数成为类的闭包)以及该函数的第一个参数,这应该是通知它使用哪个方法解析顺序(MRO)的实例或类。
因为它需要MRO的第一个参数,所以使用super与静态方法是不可能的。
Criticisms of other answers:super() lets you avoid referring to the base class explicitly, which can be
nice. . But the main advantage comes with multiple inheritance, where all
sorts of fun stuff can happen. See the standard docs on super if you haven’t
already.
这是相当有趣的,并没有告诉我们很多,但是super的目的不是为了避免写父类。重点是确保调用方法解析顺序(MRO)中的下一个方法。这在多重继承中变得重要。
我会在这里解释。
class Base(object):
def __init__(self):
print("Base init'ed")
class ChildA(Base):
def __init__(self):
print("ChildA init'ed")
Base.__init__(self)
class ChildB(Base):
def __init__(self):
print("ChildB init'ed")
super(ChildB, self).__init__()
让我们创建一个我们希望在Child之后调用的依赖项:
class UserDependency(Base):
def __init__(self):
print("UserDependency init'ed")
super(UserDependency, self).__init__()
现在请记住,ChildB使用super,ChildA不会:
class UserA(ChildA, UserDependency):
def __init__(self):
print("UserA init'ed")
super(UserA, self).__init__()
class UserB(ChildB, UserDependency):
def __init__(self):
print("UserB init'ed")
super(UserB, self).__init__()
和UserA不会调用UserDependency方法:
>>> UserA()
UserA init'ed
ChildA init'ed
Base init'ed
但是UserB,因为ChildB使用super,所以!
>>> UserB()
UserB init'ed
ChildB init'ed
UserDependency init'ed
Base init'ed
Criticism for another answer
在任何情况下,你都不应该做下面的问题,而另一个答案建议,因为当你继承ChildB时,你一定会得到错误:
super(self.__class__, self).__init__() # Don't do this. Ever.
(这个答案不是很聪明或者特别有趣,但是尽管在评论中有直接的批评,还有超过17个投票,回答者仍然坚持这样做,直到一位好心的编辑解决了他的问题。)
解释:这个答案建议调用超级像这样:
super(self.__class__, self).__init__()
这完全是错误的。 super让我们查看MRO中的下一个父级(参见本答案的第一部分)。如果你告诉super我们在子实例的方法中,它会查找下一个方法(可能是这个),导致递归,可能导致逻辑失败(在回答者的例子中, )或超过递归深度时的RuntimeError。
>>> class Polygon(object):
... def __init__(self, id):
... self.id = id
...
>>> class Rectangle(Polygon):
... def __init__(self, id, width, height):
... super(self.__class__, self).__init__(id)
... self.shape = (width, height)
...
>>> class Square(Rectangle):
... pass
...
>>> Square('a', 10, 10)
Traceback (most recent call last):
File "", line 1, in
File "", line 3, in __init__
TypeError: __init__() missing 2 required positional arguments: 'width' and 'height'
未经作者同意,本文严禁转载,违者必究!