Python从父包导入子模块报错ValueError的解决方案求助
首先先明确你的项目结构(注意common目录下存在重复的__init__.py,建议删掉其中一个,避免包识别混乱):
. ├── README.md ├── common │ ├── __init__.py │ ├── analysis │ │ ├── __init__.py │ │ └── base_analysis.py │ ├── logger.py │ └── # 此处重复的__init__.py建议删除 └── scripts └── test_analysis └── run.py
你遇到的错误核心原因是运行脚本的方式导致Python识别的顶级包范围出错:当你在scripts/test_analysis目录下直接执行python run.py时,Python会把当前目录(scripts/test_analysis)加入到sys.path的最前端,此时common包并不在Python的模块搜索路径里;同时当base_analysis.py被导入时,Python无法正确识别它属于common这个父包,导致相对导入from ..logger import Logger试图跳出当前的顶级包范围,从而触发报错。
下面给你几个可行的解决方案:
方案一:使用绝对导入,同时把项目根目录加入搜索路径
在run.py的最开头添加代码,将项目根目录(也就是包含README.md的目录)加入Python的模块搜索路径:
import sys from pathlib import Path # 逐层向上获取项目根目录:run.py -> test_analysis -> scripts -> 根目录 project_root = Path(__file__).parent.parent.parent sys.path.append(str(project_root))
之后在base_analysis.py里就可以改用绝对导入:
from common.logger import Logger
这种方式的好处是,不管你在哪里运行run.py,Python都能准确找到common包。
方案二:使用-m参数以模块方式运行脚本
回到项目根目录下,用Python的-m参数来运行run.py,把整个项目作为顶级包:
python -m scripts.test_analysis.run
这种方式下,Python会自动把项目根目录识别为顶级包所在路径,common和scripts都会被当作顶级包的子模块。此时base_analysis.py里的相对导入from ..logger import Logger就能正常工作——因为common.analysis的父包就是common,完全在顶级包的范围内。
方案三:清理重复的__init__.py文件
你的common目录下存在两个同级的__init__.py,这属于冗余配置,很容易让Python在识别包结构时出现混乱。建议删掉其中一个,保持每个包目录最多只有一个__init__.py(Python 3.3+支持无__init__.py的命名空间包,但为了兼容性和结构清晰,保留一个即可)。
内容的提问来源于stack exchange,提问作者ssk

