怎样更好的解释 Python 中的 UnboundLocalError?

2017-01-23 11:20:49 +08:00
 aragakiiyui

如题,现在只考虑一种情况, 其他情况以此类推:

a = 1
def func1():
   print(a)
   return a
    
def func2():
   print(a)
   a = a + 1
   return a

这两个函数只有 func1 可以正常执行, func2 会抛出 UnboundLocalError 异常。前者比较好解释,局部作用域没有 a ,那么会从全局作用域中去查找这个 a 。

后者我只能这样解释,就是函数体在执行前会做预先检查。如果发现有赋值语句存在,就会认为该变量名处于局部作用域中。由于函数体中有 a = a + 1 ,所以函数只在局部作用域查找 a , 然后执行的时候,发现并没有 a 这个变量,故抛出异常。

我觉得这种解释非常的绕,而且不是很直观,很容易忘记。不知道各位 v 友有什么通俗一点的方式来描述这种行为~

1948 次点击
所在节点    Python
10 条回复
est
2017-01-23 11:28:45 +08:00
global a
aragakiiyui
2017-01-23 11:32:55 +08:00
@est ......晕,这个解释不了这个问题。
lightning1141
2017-01-23 12:13:35 +08:00
因为赋值语句的存在, Python 尝试在局部作用域 (即 locals 名字空间) 中新建一个对象关联. 其实只是局部变量跟全局变量变量名冲突了. 冲突之后 Python 因为按 LEGB 顺序查找变量, 发现 a 还没有在局部作用域绑定, 所以导致了 UnboundLocalError.
```
def test1():
a = a
print(a)

def test2():
x = a
print(x)
```
第一个没问题, 第二个报错.
lightning1141
2017-01-23 12:19:14 +08:00
简单来说就是:
赋值导致了拥有这个变量名的变量只能在局部作用域查找
bxb100
2017-01-23 12:21:23 +08:00
加个 a = a 还报错吗
lightning1141
2017-01-23 12:26:28 +08:00
@lightning1141
@bxb100
说反了, 第一个报错, 第二个没问题..........
bxb100
2017-01-23 12:32:58 +08:00
@lightning1141 符合逻辑
qiu0130
2017-01-24 00:37:12 +08:00
phrack
2017-01-24 09:41:51 +08:00
以前写 c 程序的时候,偶尔也会有出乎意料的结果,但是我一直有个办法,就是反汇编直接跟踪执行流程。

python 也一样, import dis, dis.dis(func1), dis.dis(func2), 瞬间就明了了。
IanPeverell
2017-01-24 15:51:23 +08:00
func2() 里面加一个 global a 就不会抱错了,因为这样是为了让你在修改变量的时候提醒你,你有个全局变量和你要修改的变量名称相同。
( python 3.5.2)
a = 1
def func1():
print(a)
return a

print(func1())

def func2():
global a
a += 1
print(a)
return a

print(func3())

这种情况下是不会报错的,如果仅仅是引用全局变量而不修改全局变量是不会报错的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/336399

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX