You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python全局变量为何在函数内赋值前引用触发报错?

为什么Python函数中先print变量再赋值会触发UnboundLocalError?

你猜的完全正确!这就是Python的变量绑定规则在搞事情,咱们来一步步理清楚这个问题:

先看第一个能正常运行的代码:

foo = 123
def fooBar():
    print(foo)  # 局部作用域找不到foo,向上查找并打印123
    # foo = 987
    # print(foo)
fooBar()

这段代码没问题的原因很简单:函数fooBar内部没有任何对foo的赋值操作,所以Python会按照「局部作用域 → 嵌套作用域 → 全局作用域 → 内置作用域」的顺序去查找foo,最终找到全局变量foo=123,自然能正常打印。

再看报错的代码:

foo = 123
def fooBar():
    print(foo)  # 此处报错...
    foo = 987
    print(foo)
fooBar()

触发的错误如下:

Traceback (most recent call last):
  File "python", line 9, in <module>
  File "python", line 4, in fooBar
UnboundLocalError: local variable 'foo' referenced before assignment

核心原因:Python的编译期变量标记

Python在编译函数定义的时候,会扫描整个函数体的代码。如果发现函数内部有对某个变量的赋值操作(这里就是foo = 987),它会直接把这个变量标记为局部变量——不管这个赋值语句在函数里的位置是在print之前还是之后!

所以当函数fooBar执行到print(foo)时,Python会直接去局部作用域foo,但这时候foo还没被赋值(赋值语句在后面),于是就抛出了UnboundLocalError,根本不会去全局作用域查找。

这和你一开始想的“先打印全局的123,再在赋值时出错”完全不同,因为Python的作用域判定是在编译阶段就完成的,不是运行时才临时决定的。

解决办法

如果你想在函数里既使用全局的foo,又要修改它,就需要用global关键字声明foo是全局变量:

foo = 123
def fooBar():
    global foo  # 声明foo为全局变量
    print(foo)  # 此时会直接使用全局的foo=123
    foo = 987
    print(foo)  # 打印修改后的987
fooBar()

这样Python就不会把foo当成局部变量,执行时会直接操作全局作用域里的foo,自然就不会报错了。

内容的提问来源于stack exchange,提问作者KevinSoltis

火山引擎 最新活动