在调查this question时,我遇到了单一参数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
抛出的异常是
Traceback (most recent call last):
File "untitled.py", line 8, in <module>
super(A).__init__() # throws exception
RuntimeError: super(): no arguments
我不明白为什么电话会议的位置有所不同。
众所周知,super
performs magic的零参数形式:
零参数形式仅适用于类定义,因为编译器填写必要的细节以正确检索正在定义的类,以及访问普通方法的当前实例。
但是,super
的单参数形式不存在这样的陈述。相反:
另请注意,除零参数形式外,super()不限于使用内部方法。
所以,我的问题是,幕后究竟发生了什么?这是预期的行为吗?
答案 0 :(得分:3)
在这两种情况下,都会提供一个未绑定的超级对象。当你打电话给
super(A)
时,它被调用而没有参数。在没有参数的情况下调用__init__()
时,编译器会尝试推断出参数:(来自typeobject.c第7434行,最新来源)
super.__init__
几行之后:(同上,第7465行)
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. */
当您致电 f = PyThreadState_GET()->frame;
...
co = f->f_code;
...
if (co->co_argcount == 0) {
PyErr_SetString(PyExc_RuntimeError,
"super(): no arguments");
return -1;
}
时,会绕过此推断行为,因为类型不是无。当你在未绑定的超级上调用super(A)
时 - 因为它没有被绑定,这个__init__()
调用没有被代理 - 类型参数是无和编译器试图推断。在类定义中,self参数存在并用于此目的。在外面,没有可用的参数,因此引发了异常。
换句话说,__init__
不的行为方式不同,具体取决于调用的位置 - 它的super(A)
行为不同,而且&{ #39;正是文档建议的内容。
答案 1 :(得分:1)
(注意 - 我已经基本上编辑了这个答案,与实际问题更相关。)
如果你打电话给sup = super(A); sup.__init__()
,结果与你调用sup = super()
完全一样:在一个类定义中,你得到一个超级绑定;在外面,你得到一个RuntimeError(其原因在于我的另一个答案)。
这是一个确证的片段:
In [1]: class A:
...: def __init__(self):
...: print("finally!")
...:
...:
...: class B(A):
...: def __init__(self):
...: noarg = super()
...: print("No-arg super: {}".format(noarg))
...: onearg = super(B) # creates unbound super
...: print("One-arg before: {}".format(onearg))
...: onearg.__init__() # initializes sup as if sup = super()
...: print("One-arg after: {}".format(onearg))
...: onearg.__init__() # calls B.__init__()
...:
In [2]: B()
No-arg super: <super: <class 'B'>, <B object>>
One-arg before: <super: <class 'B'>, NULL>
One-arg after: <super: <class 'B'>, <B object>>
finally!