Python模块间共享全局变量的行为差异及原因咨询
跨模块共享变量的行为困惑
我正试图理解跨模块共享变量的行为。原本以为一个模块中的全局变量可以被另一个模块访问,有时确实如此,但有时却并非如此。(我知道全局变量通常不是合适的工具,但存在一些适合使用它们的场景。)
以下是代码示例:
shared.py
globalvar=0 # 全局标量变量 globalarray1=[1,2,3] # 通过.append()修改的全局数组 globalarray2=['A','B','C'] # 通过重新赋值修改的全局数组 def set_globals(): global globalvar global globalarray1 global globalarray2 globalvar=1 globalarray1.append(4) globalarray2=['a','b','c'] print("set_globals: globalvar="+str(globalvar)) print("set_globals: globalarray1="+str(globalarray1)) print("set_globals: globalarray2="+str(globalarray2))
module.py
from paas.shared import * def _main_(): global globalvar global globalarray1 global globalarray2 set_globals() print("main: globalvar="+str(globalvar)) print("main: globalarray1="+str(globalarray1)) print("main: globalarray2="+str(globalarray2)) _main_()
运行程序后的输出:
set_globals: globalvar=1 set_globals: globalarray1=[1, 2, 3, 4] set_globals: globalarray2=['a', 'b', 'c'] main: globalvar=0 main: globalarray1=[1, 2, 3, 4] main: globalarray2=['A', 'B', 'C']
观察到的现象:
_main_函数无法看到shared模块中set_globals修改后的标量变量globalvar(修改在set_globals内生效并打印,但_main_打印的是原值)。_main_能看到同一个globalarray1——set_globals中对globalarray1执行的append(4)操作,在_main_打印时能被识别。_main_无法看到同一个globalarray2——set_globals中赋值后的globalarray2在该函数内打印正确,但_main_打印的是初始值。
补充说明:这与函数内局部变量隐藏同名全局变量的情况无关;这是两个同名但初始值不同的变量。看起来import操作创建了一个同名的新模块变量,其初始值来自导入模块中的同名变量。
有人能解释这是怎么回事吗?我只看过关于全局变量的基础教程类文档,如果有能解释此现象的文档,恳请提供相关指引。
解释
核心原因在于Python中变量赋值与可变对象修改的区别,以及from module import *的导入机制:
from paas.shared import *的本质
这种导入方式会把shared模块中所有非下划线开头的变量,复制一份到当前module.py的命名空间中。也就是说,module.py里的globalvar、globalarray1、globalarray2,一开始是shared模块对应变量的副本:- 对于不可变类型(如整数
globalvar):副本是独立的数值,和原模块的变量指向不同的内存地址。 - 对于可变类型(如列表
globalarray1、globalarray2):副本是指向同一个列表对象的引用,此时两个模块的变量共享同一个内存中的列表。
- 对于不可变类型(如整数
不同操作的影响
- 不可变类型(
globalvar):set_globals里的globalvar=1是给shared模块的globalvar重新赋值,指向了新的整数对象。但module.py里的globalvar还是原来的副本(指向0),所以看不到修改。 - 可变类型的原地修改(
globalarray1.append(4)):append是对列表对象本身进行修改,没有改变变量的引用指向。因为module.py和shared的globalarray1指向同一个列表,所以修改会被两边同时看到。 - 可变类型的重新赋值(
globalarray2=['a','b','c']):这是给shared模块的globalarray2重新指向了一个新的列表对象。而module.py里的globalarray2还是指向原来的['A','B','C']列表,所以看不到新的赋值。
- 不可变类型(
解决方法
如果想让module.py能看到shared模块中变量的所有修改,应该直接导入模块本身,而不是导入变量:# module.py修改后 import paas.shared as shared def _main_(): shared.set_globals() print("main: globalvar="+str(shared.globalvar)) print("main: globalarray1="+str(shared.globalarray1)) print("main: globalarray2="+str(shared.globalarray2)) _main_()这样所有访问都是直接操作
shared模块的命名空间,就能看到所有修改了。
内容的提问来源于stack exchange,提问作者John Elion
相关产品推荐
相关产品推荐

