Python导入对象语义疑问:为何导入的变量看似是导入时刻的拷贝
Python导入对象的底层逻辑说明
你观察到的现象和深拷贝无关,本质是Python导入语句的名称绑定机制导致的,具体逻辑如下:
核心机制解释
from module import name 语句执行时只会做两件事:
- 若目标模块未加载,先完成模块加载,拿到模块对象
- 在当前作用域创建同名本地变量,将该变量一次性绑定到模块对象中对应名称当前指向的内存对象上
模块内部对global修饰的变量赋值时,本质是修改模块级命名空间中该名称的绑定指向,让它关联到新的内存对象,这个操作不会同步修改其他作用域中已经完成的绑定关系。
测试场景对应逻辑
- 可正常运行的场景:先调用
_set_args_click修改了run模块中_ARGS的绑定指向,之后执行导入时,当前作用域的_ARGS绑定的是更新后的新实例,取值符合预期 - 异常场景:先执行导入,当前作用域的
_ARGS已经绑定到初始的空RestrictedDotDict实例,之后调用_set_args_click仅修改了run模块自身的_ARGS绑定,不会影响当前作用域已存在的绑定关系,所以拿到的是未初始化的旧值
解决方案
如果需要实时获取模块中变量的最新值,不要直接导入变量名,改为导入整个模块,通过模块属性访问即可:
from . import run # 导入整个模块 ... def main(**kwargs) -> int: run._set_args_click(click.get_current_context().params) # 每次访问模块属性都会拿到最新的绑定值 if run._ARGS.context and not run._ARGS.no_console: ... return 0 ... return 0
官方术语说明
该规则属于Python执行模型中的**名称绑定(name binding)**机制,Python的每个名称绑定都归属独立的命名空间,跨命名空间的名称导入仅做一次性的对象指向绑定,不会建立动态联动关系。
内容的提问来源于stack exchange,提问作者Alexey Orlov
相关产品推荐
相关产品推荐

