You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python 3.6中如何处理“扁平化”相对导入?

解决Makefile调用脚本时的模块导入问题

我懂你已经仔细读过《Relative imports for the billionth time》那篇神文,但还是被项目里「通过Makefile运行脚本+跨子模块依赖」的导入问题绊住了对吧?结合你的需求——用make preprocessing/make train分别运行指定脚本,同时让所有模块始终从项目顶层加载,我给你两个最实用的解决方案:

方案1:通过Makefile设置PYTHONPATH(最直接)

先明确下常见的项目结构示例(如果你的结构略有不同,调整路径即可):

your_project/
├── Makefile
├── src/
│   ├── __init__.py
│   ├── data/
│   │   ├── __init__.py
│   │   └── process.py
│   └── models/
│       ├── __init__.py
│       └── train_model.py
└── utils/
    ├── __init__.py
    └── common.py

在你的Makefile里,直接把项目顶层目录加入Python的搜索路径,然后调用脚本:

# 获取当前Makefile所在的项目顶层目录
PROJECT_ROOT := $(shell pwd)

preprocessing:
	PYTHONPATH=$(PROJECT_ROOT) python src/data/process.py

train:
	PYTHONPATH=$(PROJECT_ROOT) python src/models/train_model.py

为什么这招管用?

设置PYTHONPATH=$(PROJECT_ROOT)后,Python会把项目顶层当成模块搜索的根目录,你的所有脚本里都可以用绝对导入,比如在process.py里直接写:

from utils.common import load_raw_data
from src.models.feature_utils import extract_features

完全不用纠结from ..xxx import ...这种相对导入的层级问题,跨子模块的依赖也能直接解决。

方案2:用python -m以模块方式运行(更符合Python规范)

如果不想手动设置PYTHONPATH,可以利用Python的模块运行机制,前提是所有子目录都要有__init__.py(空文件就行,用来标记这是一个Python模块)。

修改Makefile如下:

preprocessing:
	python -m src.data.process

train:
	python -m src.models.train_model

注意事项

  • 脚本里的执行代码一定要放在if __name__ == "__main__":块里,不然当其他模块导入这个脚本时,会意外执行主逻辑。
  • 这种方式同样会把项目顶层作为模块根目录,脚本里依然用绝对导入即可,跨子模块依赖轻松解决。

避坑提醒

千万别在脚本里用sys.path.append("/硬编码的路径")这种方式,换个环境或者项目目录移动后直接失效,用上面两种Makefile层面的方案才是稳定可靠的。

内容的提问来源于stack exchange,提问作者tmo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:44:21