Python导入项目子包遇问题:DDD玩具项目模块导入报错求解
问题背景
我在Python中搭建一个DDD玩具项目,通过目录结构区分共享概念和特定限界上下文,但导入模块时频繁碰到No module named错误。
项目结构如下:
. └── src/ ├── Book/ │ ├── application │ ├── domain/ │ │ ├── Book.py │ │ └── __init__.py │ ├── infrastructure │ └── __init__.py └── Shared/ ├── application ├── domain/ │ ├── Properties/ │ │ ├── __init__.py │ │ └── UuidProperty.py │ ├── ValueObjects/ │ │ ├── __init__.py │ │ └── BookId.py │ └── __init__.py └── infrastructure
在src/Book/domain/Book.py中尝试导入BookId:
from Shared.domain.ValueObjects.BookId import BookId class Book: bookId: BookId pages: int
试过手动添加目录到PYTHONPATH或用sys.path.insert的方式,但觉得不够Pythonic;给src目录添加__init__.py后尝试from src.Shared.domain.ValueObjects.BookId import BookId也未成功;还看到有些仓库用setuptools安装src包来支持单元测试导入,不确定这种方式是否适合包内导入场景。
推荐解决方案:使用setuptools可编辑安装
这是最符合Python包规范的解决方案,既能解决包内跨模块导入问题,也能完美支持单元测试和后续的包分发需求。
步骤1:添加配置文件
在项目根目录(和src同级的目录)创建pyproject.toml文件,写入以下内容:
[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] name = "ddd-toy-project" version = "0.1.0" packages = ["Book", "Shared"] package_dir = {"": "src"}
这个配置告诉setuptools,你的所有包都位于src目录下,顶层包为Book和Shared。
步骤2:执行可编辑安装
在项目根目录运行以下命令:
pip install -e .
-e参数表示"可编辑模式",后续修改代码无需重新安装,Python就能自动识别最新内容。
步骤3:修改导入语句
现在可以直接使用顶层包名进行绝对导入,和你最初的写法一致:
from Shared.domain.ValueObjects.BookId import BookId
为什么之前的尝试失败?
- 给
src添加__init__.py后用from src.Shared...导入失败,是因为Python默认不会将项目根目录加入sys.path,只有从根目录运行脚本或手动添加路径才有效,这不符合Python包的规范用法。 PYTHONPATH和sys.path.insert的问题在于依赖环境配置,换机器或环境就需要重新设置,不利于团队协作和项目部署。
补充:关于相对导入
如果是同一个限界上下文内部(比如Book包内的模块互相导入),可以使用相对导入(比如from ..domain import xxx),但跨限界上下文(如Book到Shared)的导入,绝对导入更清晰,也更符合DDD的边界划分理念,因此优先推荐绝对导入+可编辑安装的方案。
内容的提问来源于stack exchange,提问作者sverdejot

