.jpg)
网友问题:
为什么使用?super()使用 和 之间有区别吗?Base.__init__super().__init__
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()
我们使用的原因是,可能使用协作多重继承的子类将在方法解析顺序 (MRO) 中调用正确的下一个父类函数。super
在 Python 3 中,我们可以这样称呼它:
class ChildB(Base):
def __init__(self):
super().__init__()
在 Python 2 中,我们需要使用定义类的名称和 进行这样的调用,但从现在开始我们将避免这种情况,因为它是多余的、更慢的(由于名称查找)和更冗长(所以如果你还没有更新你的 Python!superself
super(ChildB, self).__init__()
如果没有 super,您使用多重继承的能力就会受到限制,因为您可以硬连线下一个父级的调用:
Base.__init__(self) # Avoid this.
我在下面进一步解释。
“这段代码实际上有什么区别?:”
class ChildA(Base):
def __init__(self):
Base.__init__(self)
class ChildB(Base):
def __init__(self):
super().__init__()
此代码的主要区别在于,在 中获取了 with 中的间接层,该层使用定义它的类来确定要在 MRO 中查找的下一个类。ChildB__init__super__init__
我在规范问题“如何在Python中使用”super“?的答案中说明了这种差异,它演示了依赖注入和协作多重继承。
super以下是实际上非常等同的代码(它是如何在 C 中实现的,减去一些检查和回退行为,并转换为 Python):super
class ChildB(Base):
def __init__(self):
mro = type(self).mro()
check_next = mro.index(ChildB) + 1 # next 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) 的实例或类。__class__
由于它需要 MRO 的第一个参数,因此不可能使用静态方法,因为它们无法访问调用它们的类的 MRO。super
super() 可以避免显式引用基类,这可能很好。.但主要优势来自多重继承,可以发生各种有趣的事情。如果您还没有,请参阅超级上的标准文档。
它相当手挥手,并没有告诉我们太多,但重点不是避免编写父类。关键是要确保调用方法解析顺序 (MRO) 中的下一个方法。这在多重继承中变得很重要。super
我将在这里解释。
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().__init__()
让我们创建一个我们希望在 Child 之后调用的依赖项:
class UserDependency(Base):
def __init__(self):
print("UserDependency init'ed")
super().__init__()
Now remember, uses super, does not:ChildBChildA
class UserA(ChildA, UserDependency):
def __init__(self):
print("UserA init'ed")
super().__init__()
class UserB(ChildB, UserDependency):
def __init__(self):
print("UserB init'ed")
super().__init__()
并且不调用 UserDependency 方法:UserA
>>> UserA()
UserA init'ed
ChildA init'ed
Base init'ed
<__main__.UserA object at 0x0000000003403BA8>
但实际上调用用户依赖关系,因为调用:UserBChildBsuper
>>> UserB()
UserB init'ed
ChildB init'ed
UserDependency init'ed
Base init'ed
<__main__.UserB object at 0x0000000003403438>
在任何情况下,您都不应该执行以下操作,这是另一个答案所暗示的,因为当您对 ChildB 进行子类时,您肯定会收到错误:
super(self.__class__, self).__init__() # DON'T DO THIS! EVER.
(这个答案并不聪明,也不是特别有趣,但尽管评论中直接批评和超过17个反对票,回答者坚持建议它,直到一个好心的编辑解决了他的问题。
说明:使用 中作为类名的替代品将导致递归。 让我们在 MRO 中查找子类的下一个父类(请参阅本答案的第一部分)。如果您告诉我们在子实例的方法中,它将查找行中的下一个方法(可能是此方法),从而导致递归,可能会导致逻辑故障(在回答者的示例中,确实如此)或超过递归深度。self.__class__super()supersuperRuntimeError
>>> 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 "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
TypeError: __init__() missing 2 required positional arguments: 'width' and 'height'
幸运的是,Python 3 没有参数的新调用方法允许我们回避这个问题。super()

网友回答:
super()让您避免显式引用基类,这可能很好。但主要优势来自多重继承,可以发生各种有趣的事情。如果您还没有,请参阅超级上的标准文档。
请注意,语法在Python 3.0中发生了变化:你可以说哪个IMO更好。标准文档还参考了使用指南,该指南具有很强的解释性。super().__init__()super(ChildB, self).__init__()super()

网友回答:
值得注意的是,在Python 3.0+中,您可以使用
super().__init__()
进行调用,简洁明了,不需要显式引用父 OR 类名,这可能很方便。我只想补充一点,对于 Python 2.7 或更低版本,有些人通过编写而不是类名来实现名称不敏感的行为,即self.__class__
super(self.__class__, self).__init__() # DON'T DO THIS!
但是,这会中断对从类继承的任何类的调用,其中可能会返回子类。例如:superself.__class__
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,以便我可以重新实现其他一些方法。SquareRectangleSquareRectangle
当我创建一个使用 时,Python 调用构造函数,因为我没有给出它自己的构造函数。但是,在 的构造函数中,调用将返回 的超类,因此它再次调用构造函数 。正如@S_C所提到的,无限循环就是这样发生的。在这种情况下,当我运行时,我正在调用构造函数,但由于我没有给它任何参数,所以我会得到一个错误。SquaremSquare = Square('a', 10,10)RectangleSquareRectanglesuper(self.__class__,self)mSquareRectanglesuper(...).__init__()Rectangle
模板简介:该模板名称为【了解 Python super() 和 __init__() 使用方法】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【Python】栏目查找您需要的精美模板。