Python自定义包安装后import子模块报错解决方案
问题原因
导入报错是Python模块搜索路径的匹配逻辑导致的,和common是否为包的本地子模块无关:
- 本地开发时如果直接在
package目录下运行脚本,Python会自动把当前工作目录加入sys.path,此时common目录刚好处于搜索路径的顶层,因此from common.helper import func可以正常执行 - 打包安装到虚拟环境/全局环境后,包会被部署到
site-packages/package路径下,Python的模块搜索路径仅包含site-packages目录,不会递归搜索子目录,自然找不到顶层名为common的模块,最终抛出导入错误
只要setup.py配置正确,common默认就是package的本地子模块,不需要额外做特殊定义。
解决方案
方案1:显式绝对导入(PEP8官方推荐)
你测试过的全路径导入写法就是标准合规的方案,显式声明模块完整路径,不存在命名冲突风险,可读性最好:
# package/main.py 内的导入语句 from package.common.helper import func
需要确保setup.py配置了正确的包发现规则,避免打包时遗漏common子目录,参考配置如下:
from setuptools import setup, find_packages setup( name="your-package-name", version="0.1.0", packages=find_packages(), # 自动递归识别所有子包,包括package、package.common # 其余配置项按实际需求填写 )
方案2:包内相对导入
如果不想每次导入都写顶层包名前缀,可以使用Python原生的相对导入语法,用.指代当前模块所在的包路径,这种写法不依赖顶层包名,只要包内部目录结构不变,无论包怎么安装、甚至修改顶层包名,导入逻辑都能正常运行:
# package/main.py 内的导入语句,单个.代表当前包(即package目录) from .common.helper import func
注意:使用相对导入时,不能直接进入
package目录执行python main.py启动脚本,需要在项目根目录下以模块方式运行:python -m package.main,否则Python会将脚本识别为顶层入口,无法解析相对导入路径。
不推荐的做法
不要为了缩短导入路径将common目录移动到和setup.py同级的顶层位置,这种操作会将common变为全局顶层模块,极容易和其他第三方包、用户业务代码中的同名common模块产生命名冲突,属于Python打包的典型反模式。
内容的提问来源于stack exchange,提问作者Levi
相关产品推荐
相关产品推荐

