super()究竟在Python 3中返回什么?

Asa*_*svi 8 python inheritance python-3.x

从Python3的文档super()"返回一个代理对象,它将方法调用委托给父类或兄弟类的类型." 那是什么意思?

假设我有以下代码:

class SuperClass():
    def __init__(self):
        print("__init__ from SuperClass.")
        print("self object id from SuperClass: " + str(id(self)))

class SubClass(SuperClass):
    def __init__(self):
        print("__init__ from SubClass.")
        print("self object id from SubClass: " + str(id(self)))
        super().__init__()


sc = SubClass()
Run Code Online (Sandbox Code Playgroud)

我得到的输出是:

__init__ from SubClass.
self object id from SubClass: 140690611849200
__init__ from SuperClass.
self object id from SuperClass: 140690611849200

这意味着,在该线super().__init__(),super()正在返回其然后隐式地传递到父类的当前对象__init__()的方法.这是准确的还是我错过了什么?

简单来说,我想了解以下内容:

什么时候super().__init__()跑,

  1. 究竟是什么传递给了__init__()怎么样?我们正在调用它,super()所以无论返回什么,都应该__init__()从我对Python的理解到目前为止传递给方法.
  2. 我们为什么不self进入super().__init__()

Pru*_*une 8

返回一个代理对象,该方法将方法调用委托给父类或兄弟类的类型.

proxy是一个充当父类的方法调用部分的对象.这不是班级本身; 相反,它只是足够的信息,因此您可以使用它来调用父类方法.

如果您打电话__init__(),您将获得自己的本地子类__init__功能.当您调用时super(),您将获得该代理对象,该对象将重定向到父类方法.因此,当您调用时super().__init__(),该代理会将调用重定向到父类__init__方法.

同样,如果您要调用super().foo,您将从foo父类中获取该方法 - 再次由该代理重新路由.

你明白了吗?


对OP评论的回应

但这必须意味着在运行super()时将此代理对象传递给 init().init()对不对?

错误.代理对象就像包名,例如调用math.sqrt().你没有将数学传递给sqrt,你用它来表示你正在使用哪个sqrt.如果你想将代理传递给init,那么调用将是init(super()).当然,这种呼吁在语义上是荒谬的.

当我们必须实际传入self时,我的例子中是sc对象.

不,你没有进来sc; 那就是结果对象创建呼叫(内部方法__new__),其中包括的调用init.因为__init__,该self对象是Python运行时系统为您创建的新项目.对于大多数类方法,第一个参数(在其他语言中称为self约定this)是调用该方法的对象.


dir*_*obs 5

这意味着,在该线super().__init__()super()正在返回其然后隐式地传递到父类的当前对象__init__()的方法。这是准确的还是我在这里遗漏了什么?

>>> help(super)  
super() -> same as super(__class__, <first argument>)
Run Code Online (Sandbox Code Playgroud)

super call 返回一个代理/包装器对象,它记住:

  • 实例调用 super()

  • 调用对象的类

  • 调用的类 super()

这是完美的声音。super始终获取具有您要查找的属性的层次结构中的下一个类(实际上是 MRO)的属性。所以它不是返回当前对象,而是更准确地说,它返回一个对象,它记住足够的信息来搜索类层次结构中更高的属性。


  1. 究竟传递给什么__init__()以及如何传递?我们正在调用它,super()所以无论返回什么,都应该根据__init__()我目前对 Python 的理解传递给方法。

你几乎是对的。但super喜欢捉弄我们。super类定义__getattribute__,该方法负责属性搜索。当您执行以下操作时:super().y()super.__getattribute__被称为搜索y。一旦它找到y它传递的是真实调用实例super调用y。另外,superhas__get__方法,使它成为一个描述符,这里我将省略描述符的详细信息,请参阅文档以了解更多信息。这也回答了您的第二个问题,即为什么self没有明确通过。

*注意:super有点不同,依​​赖于一些魔法。几乎所有其他类的行为都是相同的。那是:

a = A()  # A is a class 
a.y()    # same as A.y(a), self is a 
Run Code Online (Sandbox Code Playgroud)

super不同的是:

class A:
    def y(self):
        return self
class B(A):
    def y(self)
        return super().y()   # equivalent to: A.y(self)
b = B()
b.y() is b  # True: returns b not super(), self is b not super()
Run Code Online (Sandbox Code Playgroud)