Python 3.8(MacOS)包内模块导入报错求助:ModuleNotFoundError与ImportError问题排查
嘿,我之前在自定义Python包的导入上踩过一模一样的坑,特别懂这种明明按资料说的做了却报错的崩溃感!让我给你拆解一下问题根源和靠谱的解决办法:
为什么你的导入会报错?
核心问题出在Python识别包结构的方式上:
- 当你直接运行某个脚本(比如
python dir_1/file_1.py)时,Python会把这个脚本所在的目录(也就是practice_dir/dir_1/)加到sys.path的最前面,而不是整个practice_dir的根目录。这就导致你用from dir_2 import file_2时,Python找不到dir_2——它根本不在当前的搜索路径里。 - 相对导入(用
.或..)的报错更直接:当你直接运行脚本时,Python会把它当作顶级独立脚本,而不是包的一部分,自然就找不到所谓的“父包”,所以会抛出attempted relative import with no known parent package。
至于你看到的“Python3.3+无需__init__.py”,指的是namespace package(命名空间包),那是用于多个分散目录共享同一个包名的场景,你的情况是单一结构的常规包,保留空的__init__.py完全没问题,反而能让包结构更清晰。
靠谱的解决方案(按推荐程度排序)
方案一:用-m参数从外部运行包(官方推荐)
这是最规范的方式,能让Python正确识别整个包的结构:
- 先切换到
practice_dir的父目录(也就是你的~/目录,因为practice_dir在~/下) - 运行命令:
python -m practice_dir.dir_1.file_1 - 这时你就能正常使用导入了:
- 绝对导入:
from practice_dir.dir_2 import file_2 - 相对导入:
from ..dir_2 import file_2(..代表当前模块的父目录,也就是practice_dir根目录)
- 绝对导入:
方案二:手动把根目录加入sys.path(临时应急)
如果你不想每次都用-m参数,可以在脚本开头加一段代码,强制把practice_dir根目录加入Python的搜索路径:
import sys import os # 获取当前脚本所在目录的父目录(即practice_dir根目录) root_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if root_dir not in sys.path: sys.path.append(root_dir) # 现在就能正常导入了 from dir_2 import file_2
不过这个方法是“治标不治本”,如果以后移动了practice_dir的位置,这段代码可能会失效,适合临时测试用。
方案三:把包安装为可编辑模式(长期开发首选)
如果你打算长期维护这个包,推荐用pip把它安装成可编辑模式,这样Python会全局识别你的包:
- 进入
practice_dir根目录,创建一个setup.py文件:from setuptools import setup, find_packages setup( name="practice_dir", version="0.1", packages=find_packages() ) - 运行安装命令:
(最后的pip install -e ..代表当前目录,-e表示“可编辑”,以后修改包内代码不需要重新安装) - 之后不管你在哪里运行脚本,都可以直接用绝对导入:
from practice_dir.dir_2 import file_2,相对导入也能正常工作(只要你是作为包的一部分运行)
额外注意事项
- 绝对不要在包的内部直接运行脚本(比如
cd dir_1 && python file_1.py),这种方式会破坏Python对包结构的识别,一定要用-m参数或者安装包后运行。 - 空的
__init__.py完全没问题,不需要在里面加任何导入语句,除非你想对外暴露特定的模块或变量。
内容的提问来源于stack exchange,提问作者orie
相关产品推荐
相关产品推荐

