调用`super(some_cls)`有特殊机制?单参数super行为差异解析
super()在类内部和外部调用表现不同? 这个问题的核心在于单参数super返回的是未绑定的super对象,以及Python在实例方法中自动传递self的机制,我们一步步拆解:
1. 单参数super的本质
当你调用super(A)时,返回的是一个没有绑定任何实例的super对象。它的作用是获取A的父类,但没有关联具体的实例——这意味着,当你调用这个super对象的方法(比如__init__)时,必须手动传入一个实例作为第一个参数,就像调用未绑定的类方法一样。
2. 类内部调用为何正常?
在类A的__init__方法内部,你调用super(A).__init__()时,Python的实例方法调用规则会自动把当前的self(也就是A的实例)作为第一个参数传递给__init__。这时候实际执行的代码等价于:
super(A, self).__init__()
而双参数super(cls, instance)是完全合法的,它会绑定实例self,找到A的父类(这里是object)的__init__方法,并传入self执行——object.__init__(self)本身是合法的(虽然它什么都不做),所以不会报错。
3. 类外部调用为何抛出异常?
在类外部,没有自动传递的self参数,你直接调用super(A).__init__()时,相当于给__init__传递了0个参数。但object.__init__需要一个实例参数,同时未绑定的super对象在调用方法时,会检查是否有足够的参数来完成绑定,这时候就会抛出RuntimeError: super(): no arguments的错误——本质是因为缺少了绑定实例的参数。
如果我们手动传入一个实例,外部调用也能正常运行:
class A(): def __init__(self): super(A).__init__() a = A() super(A).__init__(a) # 手动传入实例,不会报错
4. 这是预期行为吗?
是的,这完全符合Python的设计规范。官方文档提到非零参数的super()不局限于方法内部使用,指的是你可以在任何地方创建单/双参数的super对象,但调用其方法时必须遵循绑定规则:
- 双参数
super(cls, instance)已经绑定了实例,调用方法时不需要额外传实例; - 单参数
super(cls)未绑定实例,调用方法时必须显式传入实例作为第一个参数。
类内部的“正常运行”只是Python自动帮你传了self的巧合,并不是单参数super有什么特殊的内部豁免机制。
内容的提问来源于stack exchange,提问作者Aran-Fey

