Python全局与函数作用域问题:为何读取全局变量无错赋值报错
Python作用域规则解释
问题代码
def take_damage(): health -= 20 # UNDERSTANDABLE ERROR def check_health(): if (health <= 0): # WHY NO ERROR HERE, TOO? print("You have died!") quit() else: print("Your health is "+ str(health)) # HOW DOES IT WORK HERE? health = 100 take_damage() check_health()
核心规则说明
你观察到的差异本质是Python对函数内部变量的读取操作和赋值操作的判定逻辑完全不同:
- 只要函数内部出现了对某个变量的赋值行为(包括
=、+=、-=等所有写操作),Python在编译函数阶段就会将这个变量标记为局部作用域变量,运行时只会在函数局部查找该变量,找不到就抛出UnboundLocalError。
对应take_damage函数的逻辑:health -= 20属于隐式赋值,所以Python将health判定为局部变量,但执行减操作前局部作用域没有定义过health,因此报错,这和你已知的结论一致。 - 如果函数内部只有对某个变量的读取操作,没有任何赋值操作,Python不会将其标记为局部变量,运行时会按照LEGB顺序逐层向上查找变量:
- L(Local):当前函数的局部作用域
- E(Enclosed):外层嵌套函数的闭包作用域
- G(Global):当前模块的全局作用域
- B(Built-in):Python内置作用域
只要在任意一层找到对应变量就直接使用,找不到才会抛出NameError。
对应check_health函数的逻辑:整个函数内只有对health的读取判断、类型转换操作,没有赋值行为,因此Python会逐层向上查找,最终找到全局定义的health = 100,完全符合运行规则,不会报错。
补充说明
如果需要在函数内部修改全局变量,必须显式添加global 变量名声明,告知Python该变量不需要判定为局部变量,直接使用全局作用域的对应变量即可。
内容的提问来源于stack exchange,提问作者dadiletta
相关产品推荐
相关产品推荐

