Python模块全局变量
Python模块全局变量
遇到的问题
我有一个主程序文件和两个模块文件,模块B定义了一个全局变量,最开始为None,主程序根据命令行参数将它重新绑定到一个类对象,模块A再引用这个变量时,发现还是None。
1 | # B.py |
1 | # A.py |
1 | # main.py |
运行python main.py
,所有的结果都是None。
两种import的区别
在 Python 中,模块(module)就是一个 Python 文件(*.py
)。模块有自己的独立命名空间,模块中的变量、函数、类等都属于这个命名空间。我们有两种方式使用模块中的函数或变量,import module
和from module import ..
,这两个操作的行为有一些差异。
当使用 import module
时:
- 首次导入:
- Python 会将模块代码加载到内存中,并创建一个新的命名空间来存储模块中的变量、函数和类。
- 模块会被注册到
sys.modules
,后续导入直接从缓存中读取。
- 模块是独立的:
- 每个模块都有自己的命名空间,变量、函数不会泄漏到其他模块中。
- 如果要访问另一个模块中的变量,必须显式使用
module.variable
。
1 | # moduleA.py |
1 | # main.py |
而from module import variable
的作用是将模块中的某个变量(或者函数、类)直接导入到当前命名空间。在 Python 中,一切皆对象。变量并不是数据本身,而只是对存储的数据对象的引用。使用 from module import variable
导入的变量是模块变量的引用拷贝,这相当于静态拷贝了原有模块变量的地址,当模块变量重新绑定到一个新的地址后,这个导入的变量不会动态发生改变。
1 | # moduleC.py |
1 | # main.py |
原有程序的错误
1 | # B.py |
global_yang
初始值为None
。- 调用
initialize_yang()
时,将global_yang
重新绑定到一个新的Yang
实例。
1 | # A.py |
from B import global_yang
导入了global_yang
的值(当前为None
)。- 这里的
global_yang
是B.global_yang
的引用拷贝。 - 后续如果
B.global_yang
被重新绑定,A.py
中的global_yang
不会同步变化。
1 | # main.py |
initialize_yang()
将B.global_yang
重新绑定为Yang
实例。- 但
main.py
中的global_yang
和A.py
中的global_yang
都是拷贝的旧引用,仍然指向初始的None
。
核心机制其实就是,当使用 from B import global_yang
时,Python 实际进行的操作是拷贝当前的引用值到本地命名空间。
- 导入时:
global_yang
的值为None
,因此本地的global_yang
引用指向了None
。
- 重新绑定时:
B.global_yang = Yang()
修改了模块命名空间的变量绑定。- 但本地的
global_yang
仍然指向旧的对象None
。
Python 中的这种行为是有意设计的:
- 提高性能:导入变量的拷贝比每次动态查找更快。
- 明确作用域:避免模块变量的动态绑定导致隐式修改。
怎么办
简单的方式就是不直接导入变量,而是导入整个模块,通过模块命名空间访问变量。
1 | # A.py |
1 | # main.py |
总结
1. 模块是独立命名空间
- 模块中的变量、函数、类都存在于模块自己的命名空间中。
- 使用
import module
访问时,模块变量的更新是全局可见的。
2. from ... import ... 是引用拷贝
- 使用
from module import variable
导入变量时,变量的引用被拷贝到本地命名空间。 - 如果模块中重新绑定变量,本地拷贝不会反映这些更新。
3. 一句话
Python 的模块机制强调隔离性和独立性,但通过 from ... import ...
可能导致静态引用问题,因此推荐优先使用 import module
,确保代码清晰、动态且可维护。