当我调用 `super(some_cls)` 时会发生什么魔法吗? [英] Does any magic happen when I call `super(some_cls)`?

查看:28
本文介绍了当我调用 `super(some_cls)` 时会发生什么魔法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

While investigating this question, I came across this strange behavior of single-argument super:

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

Calling super(some_class).__init__() works inside of a method of some_class (or a subclass thereof), but throws an exception when called anywhere else.

代码示例:

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

a = A()
super(A).__init__()  # throws exception

抛出的异常是

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

<小时>

我不明白为什么呼叫的位置会有所不同.


I don't understand why the location of the call makes a difference.

众所周知,super 的零参数形式施展魔法:

It's well-known that the zero-argument form of super performs magic:

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

The zero argument form only works inside a class definition, as the compiler fills in the necessary details to correctly retrieve the class being defined, as well as accessing the current instance for ordinary methods.

然而,对于 super 的单参数形式,不存在这样的语句.相反:

However, no such statement exists for the one-argument form of super. On the contrary:

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

Also note that, aside from the zero argument form, super() is not limited to use inside methods.

<小时>

那么,我的问题是,幕后到底发生了什么?这是预期的行为吗?


So, my question is, what exactly is happening under the hood? Is this the expected behavior?

推荐答案

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

In both cases, super(A) gives an unbound super object. When you call __init__() on that, it's being called with no arguments. When super.__init__ is called with no arguments, the compiler tries to infer the arguments: (from typeobject.c line 7434, latest source)

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. */

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

A few lines later: (ibid, line 7465)

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

当你调用 super(A) 时,这种推断行为会被绕过,因为 type 不是 None.当你在未绑定的 super 上调用 __init__() - 因为它没有绑定,这个 __init__ 调用没有被代理 - 类型参数 None 并且编译器尝试推断.在类定义中,存在 self 参数并用于此目的.在外部,没有可用的参数,因此引发了异常.

When you call super(A), this inferring behavior is bypassed because type is not None. When you then call __init__() on the unbound super - because it isn't bound, this __init__ call isn't proxied - the type argument is None and the compiler attempts to infer. Inside the class definition, the self argument is present and is used for this purpose. Outside, no arguments are available, so the exception is raised.

换句话说,super(A) 不是根据它被调用的地方表现不同——它是 super.__init__()行为不同,这正是文档所建议的.

In other words, super(A) is not behaving differently depending on where it is called - it's super.__init__() that's behaving differently, and that's exactly what the documentation suggests.

这篇关于当我调用 `super(some_cls)` 时会发生什么魔法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆