Python解释器遇错即停为何生成两种不同错误信息?
为什么两个场景会出现不同的运行时错误?
这问题问到点子上了!很多人会误以为Python是完全逐行执行、遇到错误就立刻停止,但实际上Python在处理函数的时候,会先在编译阶段做作用域分析,这就是两个场景错误不同的核心原因。
先明确两个错误的含义
- NameError:表示你引用的变量名在当前及所有外层可访问的作用域中都不存在。
- UnboundLocalError:这是NameError的子类,专门用于这种情况:变量被标记为局部变量,但在赋值之前就被引用了。
场景1:NameError的原因
看场景1的代码:
def a(): print(aa+bb) #aa=10 #bb=20 print(a())
- 编译函数
a的时候,Python扫描函数体,发现里面没有对aa或bb的赋值操作,所以会把这两个变量标记为“需要从外层作用域查找”。 - 当调用
a()时,Python先在函数a的局部作用域找aa,找不到就去全局作用域找——但全局作用域里aa和bb被注释掉了,根本不存在。 - 所以Python抛出
NameError:它找不到aa这个名字的任何定义。
场景2:UnboundLocalError的原因
这里要先提一句:你给出的场景2代码看起来有点矛盾——如果只是单纯的print(aa+bb),全局又定义了aa=10和bb=20,那运行应该输出30和None,不会报错。推测你可能是笔误,函数内部其实有对aa的赋值操作(比如aa = aa + bb,或者在print之后有aa = 30这类代码),才会触发UnboundLocalError。
假设修正后的场景2代码是这样(符合错误信息的情况):
def a(): print(aa+bb) aa = 30 # 这里有对aa的赋值操作 aa=10 bb=20 print(a())
现在解释错误原因:
- 编译函数
a的时候,Python扫描到函数内部有aa = 30这个赋值操作,立刻把aa标记为局部变量——不管这个赋值语句在函数的哪个位置,只要存在,整个函数里的aa都会被视为局部变量。 - 当调用
a()时,执行print(aa+bb),Python会去局部作用域找aa,但此时aa还没有被赋值(赋值语句在print之后),所以抛出UnboundLocalError:局部变量aa在赋值前就被引用了。 - 至于
bb,因为函数内部没有对它的赋值,Python会去全局作用域找到bb=20,所以不会报错在bb上。
总结一下核心规则
Python的变量作用域遵循“LEGB”规则,但关键是:
- 只要函数内部有对变量的赋值操作,这个变量就会被视为局部变量,不管赋值语句在代码的哪个位置。
- 如果函数内部没有赋值操作,Python会依次从局部、外层嵌套、全局、内置作用域查找变量。
- 编译阶段的作用域标记,是导致这两个错误不同的根本原因,而不是单纯的“逐行执行遇错即停”。
内容的提问来源于stack exchange,提问作者Deepak Tatyaji Ahire
相关产品推荐
相关产品推荐

