pythonsuper_用__init __()方法理解Python super()

本文详细解释了Python中`super()`函数的作用,特别是在处理多重继承时确保正确调用MRO(方法解析顺序)中的下一个父类方法。通过示例展示了不使用`super()`可能会导致的问题,强调了在子类初始化中使用`super()`以避免显式引用基类并确保调用顺序的正确性。同时,指出了错误使用`super()`可能导致的递归错误和逻辑问题。
摘要由CSDN通过智能技术生成

我想了解一下 super()

我们使用的原因super是,可能使用协作多重继承的子类将在方法解析顺序(MRO)中调用正确的下一个父类函数。

在Python 3中,我们可以像这样调用它:class ChildB(Base):

def __init__(self):

super().__init__()

在Python 2中,我们需要像这样使用它:super(ChildB, self).__init__()

没有超级,您使用多重继承的能力有限:Base.__init__(self) # Avoid this.

我在下面进一步解释。“这段代码实际上有什么区别?:”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__with中获得了一个间接层super,它使用当前类来确定__init__要在MRO中查找的下一个类。

我在规范问题的答案中说明了这种差异,如何在Python中使用'super'?,它演示了依赖注入和协作多重继承。

如果Python没有 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对象,我们必须在任何地方编写此手动代码(或重新创建它!)以确保我们在方法解析顺序中调用正确的下一个方法!

超级如何在没有明确告知调用方法的哪个类和实例的情况下在Python 3中执行此操作?

它获取调用堆栈帧,并找到类(隐式存储为本地自由变量,__class__使调用函数成为类的闭包)和该函数的第一个参数,该参数应该是通知它的实例或类要使用的方法解决顺序(MRO)。

因为它需要MRO的第一个参数,所以使用super静态方法是不可能的。

对其他答案的批评:使用super()可以避免显式引用基类,这可能很好。。但主要优势在于多重继承,可以发生各种有趣的事情。如果您还没有,请参阅super上的标准文档。

这是相当浪漫的,并没有告诉我们太多,但重点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使用超级,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'edBase init'ed

<__main__.UserA object at 0x0000000003403BA8>

但是UserB,因为ChildB使用super,确实!:>>> UserB()UserB init'ed

ChildB init'edUserDependency init'ed

Base init'ed<__main__.UserB object at 0x0000000003403438>

对另一个答案的批评

在任何情况下都不应该执行以下操作,这是另一个答案所暗示的,因为当您继承ChildB时肯定会出错:super(self.__class__, self).__init__() # Don't do this. Ever.

(这个答案并不聪明或特别有趣,但尽管评论中有直接的批评和超过17个downvotes,但回答者坚持提出建议,直到一位善良的编辑解决了他的问题。)

说明:那个回答建议像这样调用super: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'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值