如何解决因__init__.py导入导致的循环ImportError问题?
解决Python单元测试中的循环导入问题
问题背景
开发Python 3项目时使用unittest编写单元测试,遇到循环导入导致的ImportError:被测文件periphery/foo.py从core包导入内容,而core/__init__.py又从periphery/foo.py导入Foo。需要保留core/__init__.py中的导入语句,找到不删除该导入前提下让测试正常运行的方案。
复现示例的项目结构
├───core │ bar.py │ __init__.py │ ├───periphery │ foo.py │ __init__.py │ └───tests │ __init__.py │ ├───core │ __init__.py │ └───periphery test_foo.py __init__.py
相关文件代码
core/init.py
# --- periphery --- from periphery.foo import Foo
periphery/foo.py
from core.bar import Bar def Foo(): bar = Bar() return bar
tests/periphery/test_foo.py
from unittest import TestCase from periphery.foo import Foo class Test(TestCase): def test_foo(self): """ Test that Foo() returns "bar" """ self.assertEqual(Foo(), "bar")
运行测试触发的错误
ImportError: cannot import name 'Foo' from partially initialized module 'periphery.foo' (most likely due to a circular import)
可行解决方案
方法1:使用延迟导入(Python 3.7+)
修改core/__init__.py,利用__getattr__实现按需导入,避免模块加载阶段触发循环:
# core/__init__.py def __getattr__(name): if name == "Foo": from periphery.foo import Foo return Foo raise AttributeError(f"module 'core' has no attribute '{name}'")
只有当代码实际访问core.Foo时才会执行导入,从根源上避开初始化时的循环依赖。
方法2:调整测试文件的导入顺序
在测试文件中先导入core.bar,让core模块完成初始化后再导入periphery.foo:
from unittest import TestCase # 先完成core.bar的导入,确保core模块初始化完成 from core.bar import Bar from periphery.foo import Foo class Test(TestCase): def test_foo(self): """ Test that Foo() returns "bar" """ self.assertEqual(Foo(), "bar")
注意:这种方法依赖导入顺序,稳定性较弱,适合临时调试场景。
方法3:代码重构解耦
如果项目允许,抽离共享依赖到独立模块打破循环:
- 新增
common包,将Bar移至common/bar.py periphery/foo.py改为从common.bar导入Bar- 若
core包需要Bar,也从common.bar导入
这种方式从结构上消除循环依赖,是最彻底的解决方案。
内容的提问来源于stack exchange,提问作者Christian Singer
相关产品推荐
相关产品推荐

