Python无法访问的变量赋值导致UnboundLocalError

时间:2016-08-05 17:01:09

标签: python variables scope interpreter

我试图理解Python如何在内部管理变量。

x = 10
def ex1():
    if False:
        x=1
    print(x)
ex1()

当执行ex1()时,它显示UnboundLocalError,因为局部变量' x'没有引用。

这是怎么发生的? 解析是否在初始传递中发生,只是创建符号表并指定范围,然后是在另一个传递中发生的解释,并跳过x=1因为它无法访问?

2 个答案:

答案 0 :(得分:0)

Python没有变量声明,因此在创建/使用变量时,它必须确定范围本身。 Python范围是词法,意味着它可以访问其封闭范围内的变量,它不能修改它们。 编写ex1()的方式,x = 1是ex1()的本地。但是,当你去运行ex1()时,它会尝试读取x = 10,因为它是本地的,并抛出你的UnboundLocalError。 因此,管理变量的方式是,它看到一个本地声明,运行该函数,并看到另一个本地声明,并且由于范围,不能将这两者联系起来。

答案 1 :(得分:0)

从概念上讲,这是有道理的。我不知道它是如何实现的,但我可以说明原因。

当您影响变量时,它会在本地范围内受到影响,除非您使用关键字global明确告知。如果您只访问它且没有任何影响,它将隐式使用全局变量,因为没有定义局部变量。

x = 10

def access_global():
    print x

def affect_local():
    x = 0
    print x

def affect_global():
    global x
    x = 1
    print x

access_global() # 10
affect_local()  # 0
print x         # 10
affect_global() # 1
print x         # 10

如果在嵌套函数,类或模块中执行此操作,则规则类似:

def main():
    y = 10
    def access():
        print y
    def affect():
        y = 0
        print y

    access() # 10
    affect() # 0
    print y  # 10

main()

这可能会节省数小时的痛苦调试,除非明确说明,否则永远不要覆盖父作用域的变量。

修改

反汇编python字节代码为我们提供了一些额外的信息来理解:

import dis
x = 10
def local():
    if False:
        x = 1

def global_():
    global x
    x = 1

print local
dis.dis(local)
print global_
dis.dis(global_)


<function local at 0x7fa01ec6cde8>
 37           0 LOAD_GLOBAL              0 (False)
              3 POP_JUMP_IF_FALSE       15

 38           6 LOAD_CONST               1 (1)
              9 STORE_FAST               0 (x)
             12 JUMP_FORWARD             0 (to 15)
        >>   15 LOAD_CONST               0 (None)
             18 RETURN_VALUE        
<function global_ at 0x7fa01ec6ce60>
 42           0 LOAD_CONST               1 (1)
              3 STORE_GLOBAL             0 (x)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE      

我们可以看到local函数的字节代码正在调用STORE_FASTglobal_函数调用STORE_GLOBAL

这个问题也解释了为什么将函数转换为字节代码以避免每次调用函数时都要进行编译的性能更高: Why python compile the source to bytecode before interpreting?