哪个是存储在python中的`__class__`变量,或者编译器如何知道在哪里找到它

时间:2017-08-05 13:01:06

标签: python compiler-construction cell free abstract-syntax-tree

python依赖__class__变量来cell进行super()调用。它从第一个堆栈帧中的free变量中获取此单元格。

奇怪的是,这个变量并不在locals()中,而是在你只是从__init__方法引用它时。

以这段代码为例:

class LogicGate:
    def __init__(self,n):
        print(locals())
        a = __class__
        print(locals())

当您反汇编时,您可以看到它以某种方式知道printlocals是全局变量而__class__LOAD_DEREF。在运行代码之前,编译器如何知道这一点。据我所知,localsprint__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=[])])

1 个答案:

答案 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__