Python中如何从包导入到非包模块?
首先得说清楚:你碰到的这个ValueError: Attempted relative import in non-package错误,核心原因是Python把直接运行的tests.py当成了顶层脚本,而非某个包的组成部分——相对导入(比如from ..package import file)只在包内部的模块之间生效,直接跑顶层脚本时用相对导入自然会报错。
下面给你几个实用的解决办法,按推荐程度排序:
1. 把项目安装为可编辑包(最推荐的标准做法)
这是Python项目处理导入问题的常规操作,不仅能彻底解决当前的导入问题,还能为后续的测试、打包发布铺路。
步骤超简单:
- 打开终端,切换到
app/目录(就是包含setup.py的那个文件夹) - 运行以下命令:
这个命令会把你的pip install -e .package包安装到Python环境中,而且是可编辑模式——你修改包内的代码后,不需要重新安装就能直接生效。
之后在tests.py里直接用绝对导入即可:
from package.file import 你需要导入的内容
不管你在哪个目录运行tests.py,都能正常导入了。
2. 手动把app/目录加入Python的模块搜索路径
如果不想安装包,也可以直接告诉Python去哪里找你的package,有两种实现方式:
方式一:在tests.py开头添加代码
直接在tests.py的最顶部加入这段代码,把app/目录添加到Python的搜索路径sys.path中:
import sys from pathlib import Path # 获取当前tests.py所在目录的父目录(也就是app/) app_dir = Path(__file__).parent.parent sys.path.append(str(app_dir)) # 现在就能正常导入了 from package.file import 你需要导入的内容
这种方式不需要修改终端命令,直接运行tests.py就行,但缺点是要给测试文件加额外的代码。
方式二:通过环境变量临时设置
打开终端,先切换到app/目录,然后设置PYTHONPATH环境变量再运行测试:
# Linux/macOS系统 export PYTHONPATH=$(pwd) && python tests/tests.py # Windows PowerShell $env:PYTHONPATH = (Get-Location).Path; python tests/tests.py
这个方式不需要修改代码,但每次运行测试都要先设置环境变量,适合临时测试使用。
3. 用python -m命令运行测试(可行但不推荐)
这个方法需要把tests目录也当成包来处理,你得先给tests/目录加一个空的__init__.py文件。
然后在app/目录下运行:
python -m tests.tests
此时Python会把tests当成包的一部分,你就可以在tests.py里用相对导入了:
from ..package.file import 你需要导入的内容
但这个方法的问题在于,测试代码没必要做成包,而且直接运行tests.py还是会报错,所以不是最优解。
内容的提问来源于stack exchange,提问作者riser101

