alb*_*jan 5 python compiler-construction free cell abstract-syntax-tree
python 依赖于__class__a 中的变量进行cell调用super()。free它从第一个堆栈帧中的变量获取此单元格。
奇怪的是,这个变量并不在 中locals(),而是当您从方法中引用它时__init__。
以这段代码为例:
class LogicGate:
def __init__(self,n):
print(locals())
a = __class__
print(locals())
Run Code Online (Sandbox Code Playgroud)
当您反汇编它时,您可以看到它以某种方式知道print和locals是全局变量并且__class__是LOAD_DEREF. 在运行代码之前,编译器如何知道这一点。据我所知,locals,print和只是编译器的变量名称。__class__而且这种方式是在它被复制到之前__class__突然出现的。locals()a
4 10 LOAD_DEREF 0 (__class__)
Run Code Online (Sandbox Code Playgroud)
尽管locals:
2 LOAD_GLOBAL 1 (locals)
Run Code Online (Sandbox Code Playgroud)
我这么问是因为我正在研究一个 python 到 javascript 编译器。目前,该编译器不区分printor__class__并尝试从全局范围中获取它们。
正如您从上面代码的 ast 的打印输出中看到的,解析器不区分localsor __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=[])])
Run Code Online (Sandbox Code Playgroud)
该__class__单元是 Python 3 中的一个 hack,允许super在没有参数的情况下调用。在 Python 2 中,您必须使用样板参数调用 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'>
Run Code Online (Sandbox Code Playgroud)
但是,这取决于函数,如果函数不使用单元格,co_freevars则__closure__可能是这样。None此外,__class__不保证存在。__class__仅当调用的函数不super带参数时(实际上不必是 super,例如super = print; super()会欺骗编译器创建__class__单元格)或者__class__被显式引用并且不是本地的,该单元格才存在。您也不能假设__class__单元格始终位于索引 0,如以下(尽管很奇怪)代码所示:
class A:
def greet(self, person):
print('hello', person)
def create_B(___person__):
class B(A):
def greet(self):
super().greet(___person__)
return B
B = create_B('bob')
B().greet() # prints hello bob
assert [c.cell_contents for c in B.greet.__closure__] == ['bob', B]
Run Code Online (Sandbox Code Playgroud)