
本文详解如何通过 pip install -e . 正确安装采用“ad-hoc 布局”的本地 python 项目,解决 find_packages(where='mypkg') 报错及子包无法导入的问题,并说明 package_dir 的关键作用。
在开发多层嵌套的本地 Python 项目时,常见的目录结构是将实际包代码置于子目录(如 mypkg/)下,而非直接放在项目根目录——这种布局被称为 ad-hoc layout(非标准布局)。此时若仅依赖 find_packages() 而不显式声明源码映射关系,pip install -e . 很可能失败或导致包内容为空。
你遇到的错误:
error: package directory 'subpkg1' does not exist
根本原因在于:find_packages(where='mypkg') 告诉 setuptools 去 mypkg/ 目录里找包,但 setuptools 仍默认从当前目录(即 project_root_directory)解析包路径。当它尝试验证 subpkg1 是否为合法包时,会按相对路径 subpkg1/ 查找(即根目录下的 subpkg1/),而非 mypkg/subpkg1/,因此报错——尽管该子包真实存在于 mypkg/ 内。
✅ 正确解法是同时指定两件事:
立即学习“Python免费学习笔记(深入)”;
- 源码位置(where):告诉 find_packages() 到哪里扫描;
- 包名到路径的映射(package_dir):告诉 setuptools “空字符串包名(即顶级包)” 对应的实际目录是 mypkg。
因此,你的 setup.py 应修正为:
from setuptools import setup, find_packages
setup(
name="Code",
author="Me",
author_email="Me",
description="Code",
packages=find_packages(where="mypkg"), # ✅ 扫描 mypkg/ 下的所有包
package_dir={"": "mypkg"}, # ✅ 关键!将 "" → "mypkg" 映射
python_requires=">=3.6",
)? 补充说明:package_dir={"": "mypkg"} 表示“所有未显式声明前缀的包(即顶层包 mypkg)均来自 mypkg/ 目录”。这使 find_packages(where="mypkg") 扫描到的 subpkg1、subpkg2 等能被正确定位为 mypkg.subpkg1、mypkg.subpkg2。
完成修改后,执行:
pip install -e .
即可成功以可编辑模式安装整个包结构。之后可在 Python 中正常导入:
from mypkg.subpkg1 import module1 from mypkg.subpkg2.module2 import some_function import mypkg
⚠️ 注意事项:
- 若使用 pyproject.toml(推荐现代方式),请改用 setuptools 配置块替代 setup.py,但 package-dir 和 find-package 逻辑保持一致;
- __init__.py 缺失的子目录不会被 find_packages() 发现,这是预期行为(符合 Python 包定义规范);
- IDE(如 VS Code、PyCharm)可能因缓存延迟导致 tab 补全失效,重启 Python 解释器或刷新索引即可解决,不影响实际运行时导入。
总结:find_packages(where=...) 只负责“发现”,而 package_dir 才真正决定“如何解析路径”。二者必须协同配置,才能让 ad-hoc 布局的本地项目被 pip 正确识别、安装与导入。










