为什么我在第二个代码中得到UnboundLocalError而在第一个代码中没有?

时间:2016-07-27 14:57:06

标签: python

执行时

x = 0

def f():
    print('x' in locals())
    x = 1
    print('x' in locals())

f()

我得到了我的期望,即

False
True

然而,当我执行

x = 3

def f():
    print(x, 'x' in locals())
    x = 7
    print(x, 'x' in locals())

f()

我希望得到

3 False
7 True

但我获得了UnboundLocalError

如果Python知道在下一行有一个标签x在本地范围内的分配(因此名称x已经在本地范围内但它不是但是为什么它让我在我的第一个代码中询问x

已添加

为什么即使x = 7位于第一个print(x, 'x' in locals())之后,它也会引发错误?

2 个答案:

答案 0 :(得分:2)

第一个函数

dis.dis

  2           0 LOAD_CONST               1 ('x')
              3 LOAD_GLOBAL              0 (locals)
              6 CALL_FUNCTION            0
              9 COMPARE_OP               6 (in)
             12 PRINT_ITEM
             13 PRINT_NEWLINE

  3          14 LOAD_CONST               2 (1)
             17 STORE_FAST               0 (x)

  4          20 LOAD_CONST               1 ('x')
             23 LOAD_GLOBAL              0 (locals)
             26 CALL_FUNCTION            0
             29 COMPARE_OP               6 (in)
             32 PRINT_ITEM
             33 PRINT_NEWLINE
             34 LOAD_CONST               0 (None)
             37 RETURN_VALUE
第二个功能

dis.dis

  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 ('x')
              6 LOAD_GLOBAL              0 (locals)
              9 CALL_FUNCTION            0
             12 COMPARE_OP               6 (in)
             15 BUILD_TUPLE              2
             18 PRINT_ITEM
             19 PRINT_NEWLINE

  3          20 LOAD_CONST               2 (7)
             23 STORE_FAST               0 (x)

  4          26 LOAD_FAST                0 (x)
             29 LOAD_CONST               1 ('x')
             32 LOAD_GLOBAL              0 (locals)
             35 CALL_FUNCTION            0
             38 COMPARE_OP               6 (in)
             41 BUILD_TUPLE              2
             44 PRINT_ITEM
             45 PRINT_NEWLINE
             46 LOAD_CONST               0 (None)
             49 RETURN_VALUE

关键区别是行:4 26 LOAD_FAST 0 (x)

基本上,在当前范围内有一个名为x的赋值语句,因此x被解析为本地名称。解析在编译阶段执行。编译后的字节码使用LOAD_FAST而非LOAD_GLOBAL

编译为字节码和执行是two independent steps - 语言实际上并不是逐行解释的。

答案 1 :(得分:0)

错误来自打印x,而不是来自通话'x' in locals()。当你执行x时,你实际上并没有对变量'x' in locals()做任何事情,因为你给它一个字符串值,而不是对变量的引用。