x=1
def g():
print(x)
x=2
g()
只要把函数里的 x = 2 删掉,就不会把 x 当成局部变量,也不会触发 UnboundLocalError 了:
x = 1
def g():
print(x) # 只读,x 被视为全局变量
g() # 输出 1
Python 的作用域规则 是 “赋值即局部”(LEGB 中的 L 优先):
只要函数体内出现 = 给某个名字赋值,Python 就认定这个名字是该函数的局部变量。
在真正执行赋值语句之前,这个名字在函数里尚未绑定值,于是引用到它时会抛出 UnboundLocalError。
去掉 x = 2 后,函数里没有赋值,Python 就按 LEGB 顺序去外层(Global)找 x,于是可以正常读取全局变量 x 的值。
每个函数属于一个区块,这个区块范围是一次性解释的,函数体字节码,读完整个区块再解释。所以,读完整个g()区块后,首先就记住了重新定义了本地变量x=2,于是g()中所有使用变量x的时候,都是本地变量x,所以print(x)中的x也是本地变量,但这违反了使用变量前先赋值的规则,所以也会报错。