当我调用`super(some_cls)时,有没有魔法?

Ara*_*Fey 7 python super python-3.x

在调查这个问题时,我遇到了单一参数的奇怪行为super:

调用super(some_class).__init__()some_class(或其子类)的方法内部工作,但在其他地方调用时抛出异常.

代码示例:

class A():                                                                                         
    def __init__(self):                                                         
        super(A).__init__()  # doesn't throw exception

a = A()
super(A).__init__()  # throws exception
Run Code Online (Sandbox Code Playgroud)

抛出的异常是

Traceback (most recent call last):
  File "untitled.py", line 8, in <module>
    super(A).__init__() # throws exception
RuntimeError: super(): no arguments
Run Code Online (Sandbox Code Playgroud)

我不明白为什么电话的位置有所不同.

众所周知,super 执行魔法的零参数形式:

零参数形式仅适用于类定义,因为编译器填写必要的细节以正确检索正在定义的类,以及访问普通方法的当前实例.

但是,对于单参数形式,没有这样的陈述super.反之:

另请注意,除零参数形式外,super()不限于使用内部方法.


所以,我的问题是,引擎盖下究竟发生了什么?这是预期的行为吗?

Nat*_*eks 3

在这两种情况下,super(A)都会给出一个未绑定的超级对象。当你调用__init__()它时,它会被无参数地调用。当super.__init__不带参数调用时,编译器尝试推断参数:(来自 typeobject.c 第 7434 行,最新源代码)

static int
super_init(PyObject *self, PyObject *args, PyObject *kwds)
{
    superobject *su = (superobject *)self;
    PyTypeObject *type = NULL;
    PyObject *obj = NULL;
    PyTypeObject *obj_type = NULL;

    if (!_PyArg_NoKeywords("super", kwds))
        return -1;
    if (!PyArg_ParseTuple(args, "|O!O:super", &PyType_Type, &type, &obj))
        return -1;

    if (type == NULL) {
        /* Call super(), without args -- fill in from __class__
           and first local variable on the stack. */
Run Code Online (Sandbox Code Playgroud)

几行之后:(同上,第 7465 行)

    f = PyThreadState_GET()->frame;
...
    co = f->f_code;
...
    if (co->co_argcount == 0) {
        PyErr_SetString(PyExc_RuntimeError,
                        "super(): no arguments");
        return -1;
    }
Run Code Online (Sandbox Code Playgroud)

当您调用 时super(A),会绕过此推断行为,因为类型不是 None。然后,当您调用__init__()未绑定的 super 时 - 因为它未绑定,所以该__init__调用不会被代理 - 类型参数None 并且编译器尝试推断。在类定义内部,存在 self 参数并用于此目的。在外部,没有可用的参数,因此引发异常。

换句话说,super(A)并不是根据调用位置的不同而表现不同 - 而是表现super.__init__()不同,而这正是文档所建议的。