为何Python全局变量值随脚本运行方式不同而变化?
问题描述
我编写了一个名为glbltest.py的Python示例脚本,代码如下:
a = [] def fun(): global a a = [20,30,40] print("before ",a) fun() print("after ",a)
当通过命令行运行该脚本时,输出符合预期:
$ python glbltest.py before [] after [20, 30, 40]
在Python Shell中通过from glbltest import *导入脚本时,得到如下输出:
>>> from glbltest import * before [] after [20, 30, 40]
但当注释掉脚本最后三行,手动执行操作时:
>>> from glbltest import * >>> a [] >>> fun() # 手动调用fun() >>> a # 再次查看a的值 [] # 结果不符合预期!
请问:脚本导入时自动执行fun(),与手动调用fun()这两种情况,为何会导致全局变量a的表现不同?
原因分析
核心差异在于命名空间隔离和变量绑定时机:
导入时自动执行
fun()的情况
执行from glbltest import *时,Python会先完整加载glbltest模块:- 模块内部先初始化
a = [],接着执行print("before ",a)、fun()、print("after ",a)。 fun()里的global a特指**glbltest模块自身全局命名空间中的a**,执行a = [20,30,40]会把模块内的a重新绑定到新的列表对象。- 模块加载完成后,
from glbltest import *会将模块最终的全局变量(包括已经修改后的a)复制到当前Shell的命名空间,所以后续查看的a是模块修改后的新列表,表现符合预期。
- 模块内部先初始化
手动调用
fun()的情况
注释掉脚本最后三行后,模块加载时仅初始化a = []和定义fun(),不会自动执行fun():from glbltest import *会将模块此时的a(空列表)和fun()复制到当前Shell命名空间,此时Shell里的a和模块里的a最初指向同一个空列表对象。- 手动调用
fun()时,fun()里的global a依然只作用于glbltest模块的全局命名空间,它会把模块内的a重新绑定到新列表[20,30,40],但这不会影响Shell命名空间里的a——因为Shell里的a还是指向原来的空列表对象,没有同步到新的绑定关系。 - 如果想查看模块内
a的变化,可以改为导入整个模块:>>> import glbltest >>> glbltest.a [] >>> glbltest.fun() >>> glbltest.a [20, 30, 40]
简单总结:from ... import *是把模块变量的当前引用复制到本地命名空间,后续模块内部对变量的重新绑定不会同步到本地;而直接导入模块后通过模块名访问,始终读取的是模块命名空间里的最新绑定。
内容的提问来源于stack exchange,提问作者bob.sacamento
相关产品推荐
相关产品推荐

