Python局部变量编译原理 [英] Python local variable compile principle

查看:113
本文介绍了Python局部变量编译原理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

def fun():  
    if False:
        x=3
    print(locals())
    print(x)
fun()

输出和错误消息:

{}
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-57-d9deb3063ae1> in <module>()
      4     print(locals())
      5     print(x)
----> 6 fun()

<ipython-input-57-d9deb3063ae1> in fun()
      3         x=3
      4     print(locals())
----> 5     print(x)
      6 fun()

UnboundLocalError: local variable 'x' referenced before assignment

我想知道python解释器如何工作。请注意,x = 3根本不会运行,并且不应将其视为局部变量,这意味着错误将是未定义名称 x。但是,查看代码和错误消息并非如此。有人可以在这种情况下解释python解释器编译的机制原理吗?

I am wondering how the python interpreter works. Note that x=3 doesn't run at all, and it shouldn't be treated as a local variable, which means the error would be " name 'x' is not defined". But look into the code and the error message, it isn't the case. Could anybody explain the mechanism principle of the compilation of the python interpreter behind this situation?

推荐答案

因此,Python会始终对每个名称进行分类在每个功能中分别是本地非本地全局之一。这些名称范围是排他的;在每个函数中(嵌套函数中的名称都有自己的命名范围),每个名称只能属于以下类别之一。

So, Python will always categorize each name in each function as being one of local, non-local or global. These name scopes are exclusive; within each function (names in nested functions have their own naming scope), each name can belong to only one of these categories.

Python编译此代码时:

When Python compiles this code:

def fun():
    if False:
        x=3

它将产生一个抽象的语法树,如下所示:

it will result in an abstract syntax tree as in:

FunctionDef(
    name='fun', 
    args=arguments(...), b
    body=[
        If(test=NameConstant(value=False),
            body=[
                Assign(targets=[Name(id='x', ctx=Store())], value=Num(n=3))
            ], 
            orelse=[])
    ]
)

(省略了一些内容为简洁起见)。现在,当将此抽象语法树编译为代码时,Python将扫描所有名称节点。如果存在任何 Name 节点,且 ctx = Store(),则该名称被认为是 local 到封闭的 FunctionDef (如果有),除非被 global 覆盖(即 global x )或非本地非本地x )语句。

(some stuff omitted for brevity). Now, when this abstract syntax tree is compiled into code, Python will scan over all name nodes. If there is any Name nodes, with ctx=Store(), that name is considered to be local to the enclosing FunctionDef if any, unless overridden with global (i.e. global x) or nonlocal (nonlocal x) statement within the same function definition.

ctx = Store()的出现主要是因为所用名称在分配,或作为 for 循环中的迭代变量。

The ctx=Store() will occur mainly when the name in question is used on the left-hand side of an assignment, or as the iteration variable in a for loop.

现在,当Python将其编译为字节码时,产生的字节码是

Now, when Python compiles this to bytecode, the resulting bytecode is

>>> dis.dis(fun)
  4           0 LOAD_GLOBAL              0 (print)
              3 LOAD_FAST                0 (x)
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 POP_TOP
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE

优化器删除了 if 语句完全;但是,由于该变量已被标记为该函数的局部变量,因此 LOAD_FAST 用于 x ,这将导致 x 只能从 local 变量访问,并且只能从局部变量访问。由于未设置 x ,因此将引发 UnboundLocalError 。另一方面,从未分配名称 print ,因此该名称被认为是该函数中的全局名称,因此其值将装入 LOAD_GLOBAL

The optimizer removed the if statement completely; however since the variable was already marked local to the function, LOAD_FAST is used for x, which will result in x being accessed from local variables, and local variables only. Since x has not been set, the UnboundLocalError is thrown. The name print on the other hand was never assigned to, and thus is considered a global name within this function, so its value is loaded with LOAD_GLOBAL.

这篇关于Python局部变量编译原理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆