简单的解释
查看以下文档
super():
零参数形式仅在类定义内起作用,因为编译器会填写必要的详细信息以正确检索要定义的类,以及为常规方法访问当前实例。
通过 一个类定义 他们的意思 内部类方法的范围 。内部 类方法范围 解释器能够使用与在Python
2中显式提供的参数相同的参数来完成零形式。但是列表推导创建了它自己的范围。这就是它失败的原因:您
super()不能从类方法范围调用,并且解释器无法使用所有参数来完成它。
进阶说明
根据Python数据模型:
__class__是由编译器创建如果在类身体的任何方法指任一个隐式的闭合参考__class__或super。这使得零参数形式的super()可以基于词法作用域正确地标识正在定义的类,而用于进行当前调用的类或实例是根据传递给该方法的第一个参数来标识的。
Python甚至可以在列表理解范围内
super()从
__class__变量中收集第一个参数(因为它在所有子作用域中都可以作为常规闭包使用)。您可以使用以下方法进行测试:
class T: def test(self): print(__class__) print([__class__ for _ in range(1)][0])T().test()
将输出:
<class '__main__.T'><class '__main__.T'>
但是解释器错误地为收集第二个参数
super():
self。它假定对
super()方法范围内的调用,并尝试使用以下C代码获取该方法的第一个参数(为清楚起见,省略了许多行):
PyframeObject *f = PyThreadState_GET()->frame;obj = f->f_localsplus[0];if (obj != NULL) { obj_type = supercheck(type, obj); if (obj_type == NULL) return -1; Py_INCREF(obj);}无法
f->f_localsplus[0]从Python进行访问,但根据代码中的注释,它包含“
locals + stack”。因此,我们可以利用它
locals()进行测试(不幸的是缺少订单)。让我们测试一下,在类方法和列表理解内的本地可用内容:
class T: def test(self): print(locals()) print([locals() for _ in range(1)])T().test()
将打印:
{'self': <__main__.T object at 0x100f1f8d0>}{'_': 0, '.0': <range_iterator object at 0x100fbb2a0>}在第一种情况下,有一个对我们对象的引用,解释器会正确找到它。在列表理解内,字典内没有对象,因此它将得到
0或
range_iterator(记住,顺序丢失了吗?)。这些都不是我们对象的实例。它将失败
supercheck()并给您一个错误
objmust be an instance or subtype of type(例如
T)。



