为何重复导入Python模块全局变量会生效?导入机制疑问解析
Python重复导入变量为何会更新值?
问题场景
运行main.py的输出如下:
$ python main.py var = 10 (main) "var" in globals() = True (change_var) "var" in globals() = True sub1_globals == main_globals = False var = 10 sub1_globals["var"] = 20 main_globals["var"] = 10 var is main_globals["var"] = True var is sub1_globals["var"] = False reimport var = 20
调用change_var()修改了sub1模块中的var为20,但主模块main里的var仍为10。但当在main中再次执行from sub1 import var后,main里的var变成了20。按认知Python模块仅可导入一次,为何重复导入会让变量值更新?
涉及代码
sub1.py
var = 10 def change_var(): print(f'(change_var) {"var" in globals() = }') global var var = 20 return globals()
main.py
from sub1 import var, change_var if __name__ == "__main__": print(f'{var = }') print(f'(main) {"var" in globals() = }') sub1_globals = change_var() main_globals = globals() print(f'{sub1_globals == main_globals = }') print(f'{var = }') print(f'{sub1_globals["var"] = }') print(f'{main_globals["var"] = }') print(f'{var is main_globals["var"] = }') print(f'{var is sub1_globals["var"] = }') from sub1 import var print(f"reimport {var = }")
原因解释
你对「模块仅导入一次」的认知是对的,但from ... import ...的行为和你想的不一样:
- 模块确实只会被加载一次,重复执行
import或from ... import ...不会重新运行模块的代码。 - 但
from sub1 import var的本质是:从已经加载好的sub1模块对象中,取出当前var的引用,然后覆盖当前命名空间(main的全局命名空间)里的var变量。
具体过程拆解:
- 第一次导入:
from sub1 import var把sub1模块中var的引用(指向整数10)复制到main的全局命名空间,此时main的var和sub1的var都指向10。 - 调用
change_var():函数里用global var声明操作sub1的全局var,然后将其重新赋值为20——因为整数是不可变类型,这相当于让sub1的var指向了一个新的整数对象20,但main的var还是指向原来的10,所以此时输出var=10。 - 再次导入:
from sub1 import var不会重新加载sub1.py,但会去sub1模块的全局命名空间里取当前的var(也就是指向20的引用),然后把main全局命名空间里的var替换成这个新引用,所以之后输出var=20。
如果想避免这种覆盖,可以直接导入模块,通过sub1.var访问,而不是单独导入变量:这样每次访问的都是sub1模块里的当前值,也不会被覆盖。
内容的提问来源于stack exchange,提问作者Drunkwcodes
相关产品推荐
相关产品推荐

