Python跨文件循环导入时字典变量未同步更新问题咨询
问题本质
这是Python循环导入+__main__模块特殊机制导致的命名空间隔离问题,和global声明、字典可变类型特性没关系。
你执行python runner.py的时候,整个运行逻辑是这样的:
- Python把当前执行的
runner.py注册为名为__main__的模块,开始逐行运行代码 - 第一行
import secondthread触发secondthread.py加载,执行到secondthread.py里的import runner时,Python发现还没注册过名为runner的模块,就会重新读取一遍runner.py的内容,生成一个和当前运行的__main__完全独立的runner模块,这个模块里的my_dict是空的,也从来没执行过action1() - 等
secondthread加载完成,回到__main__模块继续往下执行,调用action1()修改的是__main__模块下的my_dict,和刚才循环导入生成的那个runner模块里的my_dict完全是两个独立对象 - 最后调用
secondthread.action2()的时候,函数里读取的是独立runner模块下的空字典,自然读不到你刚写入的键i
你试的from runner import my_dict也没用:这种写法只是把runner模块里的那个空字典的引用绑定到了secondthread的本地命名空间,指向的还是那个从来没被修改过的空字典,不是你主流程里更新的那个。至于在secondthread里写global声明,更是不相关——global只管当前模块内的全局变量,跨模块根本不生效。
修复方法
按推荐优先级从高到低给三个可直接落地的方案:
- 抽离共享状态到独立模块(最规范,彻底解决循环依赖)
不要让两个业务模块互相导入,把需要共享的变量单独放到第三个公共文件里。
新建shared.py:
两个文件都从这个公共模块导入变量:my_dict = {}# runner.py import secondthread from shared import my_dict def action1(): my_dict["i"] = 2 if __name__ == "__main__": action1() secondthread.action2()
所有地方引用的都是同一个# secondthread.py from shared import my_dict def action2(): try: print("Thread2: dict value is = {}".format(my_dict["i"])) except Exception as e: print("Thread2: dict haven't got updated value, len of dict is: {}".format(len(my_dict)))shared.my_dict对象,修改后所有位置都能读到最新值,不存在循环导入隐患。 - 函数内延迟导入主模块(不想调整文件结构的快速修复)
不要在secondthread.py顶层导入runner,把导入逻辑放到action2函数内部,直接导入当前运行的__main__模块,不会触发重复加载:
注意这里不能写# secondthread.py def action2(): import __main__ as runner try: print("Thread2: dict value is = {}".format(runner.my_dict["i"])) except Exception as e: print("Thread2: dict haven't got updated value, len of dict is: {}".format(len(runner.my_dict)))import runner,否则还是会加载到那个独立的空runner模块。 - 显式传参(耦合最低的写法)
不要跨模块读取全局变量,调用函数的时候把需要用到的对象当参数传进去:# runner.py 调整调用逻辑 if __name__ == "__main__": action1() secondthread.action2(my_dict)
这种写法完全不依赖模块导入逻辑,代码可读性最高,不会出现莫名其妙的命名空间问题。# secondthread.py 调整函数定义 def action2(target_dict): try: print("Thread2: dict value is = {}".format(target_dict["i"])) except Exception as e: print("Thread2: dict haven't got updated value, len of dict is: {}".format(len(target_dict)))
内容的提问来源于stack exchange,提问作者Bertrand Tan
相关产品推荐
相关产品推荐

