Python包内模块导入最佳实践咨询及包路径系统疑难排查
首先,咱们把核心问题点透:你遇到的ModuleNotFoundError,本质是安装后的包结构和开发时的路径依赖不匹配导致的。当你用pip install .把包安装到Python的site-packages目录后,每个包(package1、package2、package3)都是独立的顶级模块,这时候你原来写的from module2 import AwsService会被Python当成“找全局的module2模块”,而不是package2下面的module2,自然就找不到了。
为什么有的模块没报错?
你提到package2的module3.py用from module2 import AwsService却没出问题,这大概率是测试时的路径巧合:当你在package2目录下直接运行测试时,pytest默认会把测试文件所在目录的父目录加入sys.path,导致src/下的模块被临时当成顶级模块能被找到。但当package2作为依赖被安装到site-packages后,这个临时路径就不存在了,所以在package1的测试环境里调用package2的模块时,就会触发报错。
什么时候用相对导入,什么时候用绝对导入?
直接给你明确的规则:
- 绝对导入(强烈推荐):用完整的包路径导入,比如package2的module1.py里写
from package2.module2 import AwsService,package3的module1.py里写from package3.module2 import xxx。这种方式不管是开发环境还是安装后的生产环境,都能精准定位模块,完全避免路径问题,也是Python官方推荐的做法。 - 相对导入:用
.(当前包)或..(父包)开头的导入,比如from .module2 import AwsService或者from . import AwsService。这种只能在包内部使用,而且不能直接运行模块脚本(比如python src/module1.py会直接报错,因为此时模块不是作为包的一部分被导入的)。如果用相对导入,必须保证包内所有内部导入都统一用相对路径,不能混合写法。
你的项目与CI流程的优化建议
确认setup.py配置(你的配置其实没问题)
你的package_dir={"package2": "src"}和packages=["package2"]是正确的,它告诉setuptools把src/下的所有内容作为package2包的一部分,安装后site-packages里会有package2/目录,包含所有模块。统一导入方式
把所有包内的内部导入改成绝对导入,比如:- package2/module1.py:
from package2.module2 import AwsService - package3/module1.py:
from package3.module2 import module2(或者具体的类/函数)
这样不管是CI环境还是本地开发,导入都不会出问题。
- package2/module1.py:
优化CI测试流程
可以把pip install .改成pip install -e .(可编辑模式安装),这样修改代码后不需要重新安装,包的结构也会被Python正确识别,同时测试时的导入逻辑和安装后的环境完全一致。
包导入的最佳实践总结
- 优先使用绝对导入,代码可读性更强,完全避免路径依赖问题。
- 如果用相对导入,确保包内所有内部导入统一使用相对路径,且不要直接运行包内的模块脚本(要用
python -m package2.module1这种方式运行)。 - 测试代码的导入也要遵循包结构,比如test_package1.py里应该写
from package1.module1 import xxx,而不是import module1。 - 开发时用
pip install -e .安装包,方便调试和测试,避免重复安装。 - 每个包的setup.py要确保
package_dir和packages配置正确,setuptools能正确识别包的结构。
内容的提问来源于stack exchange,提问作者ybonda

