You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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的表现不同?


原因分析

核心差异在于命名空间隔离和变量绑定时机:

  1. 导入时自动执行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是模块修改后的新列表,表现符合预期。
  2. 手动调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 03:15:12