python依赖__class__
变量来cell
进行super()
调用。它从第一个堆栈帧中的free
变量中获取此单元格。
奇怪的是,这个变量并不在locals()
中,而是在你只是从__init__
方法引用它时。
以这段代码为例:
class LogicGate:
def __init__(self,n):
print(locals())
a = __class__
print(locals())
当您反汇编时,您可以看到它以某种方式知道print
和locals
是全局变量而__class__
是LOAD_DEREF
。在运行代码之前,编译器如何知道这一点。据我所知,locals
,print
和__class__
只是编译器的变量名。同样,这种方式__class__
在locals()
中突然被复制到a
之前。
4 10 LOAD_DEREF 0 (__class__)
while locals
:
2 LOAD_GLOBAL 1 (locals)
我问,因为我正在研究一个python到javascript编译器。目前,编译器没有区分print
或__class__
,并尝试从全局范围获取它们。
正如您从上面的代码的打印输出中看到的那样,解析器无法区分locals
或__class__
:
Module(body=[ClassDef(name='LogicGate',
bases=[],
keywords=[],
body=[FunctionDef(name='__init__',
args=arguments(args=[arg(arg='self',
annotation=None),
arg(arg='n',
annotation=None)],
vararg=None,
kwonlyargs=[],
kw_defaults=[],
kwarg=None,
defaults=[]),
body=[Expr(value=Call(func=Name(id='print',
ctx=Load()),
# here's the load for locals
args=[Call(func=Name(id='locals',
ctx=Load()),
args=[],
keywords=[])],
keywords=[])),
Assign(targets=[Name(id='a',
ctx=Store())],
# here's the load for __class__
value=Name(id='__class__',
ctx=Load())),
Expr(value=Call(func=Name(id='print',
ctx=Load()),
args=[Call(func=Name(id='locals',
ctx=Load()),
args=[],
keywords=[])],
keywords=[]))],
decorator_list=[],
returns=None)],
decorator_list=[])])
答案 0 :(得分:2)
{3}单元格是Python 3中的一个黑客,允许在没有args的情况下调用__class__
。在Python 2中,你必须使用样板参数调用super(即。super
)。
super(<current class>, self)
单元格本身存储在__class__
元组中。可以通过在<function>.__closure__
元组中查找其索引来获得__class__
单元格的索引。例如,
<function>.__code__.co_freevars
但是,根据功能,>>> class A:
def __init__(self):
super().__init__()
>>> A.__init__.__code__.co_freevars
('__class__',)
>>> A.__init__.__closure__
(<cell at 0x03EEFDF0: type object at 0x041613E0>,)
>>> A.__init__.__closure__[
A.__init__.__code__.co_freevars.index('__class__')
].cell_contents
<class '__main__.A'>
和co_freevars
可能是__closure__
,如果该功能不使用单元格。此外,不保证None
存在。只有在没有args的情况下调用名为__class__
的函数时才会出现__class__
单元格(实际上不必是超级的。super
会欺骗编译器创建super = print; super()
} cell)或__class__
是否显式引用且不是本地的。您也不能假设__class__
单元始终位于索引0处,因为以下(尽管很奇怪)代码显示:
__class__