如何统一Python导入规则,同时支持脚本运行与外部包组件导入
问题根源
该冲突本质是Python的模块搜索路径sys.path在两种运行场景下不一致导致的:
- 在
app目录下执行python script.py时,Python会自动将当前工作目录(也就是app文件夹)加入sys.path,此时直接导入utils可正常识别,但app.utils无法识别,因为app的上层目录work不在搜索路径中。 - 在
work目录下打开analysis.ipynb时,Python会自动将work目录加入sys.path,此时app.utils可正常识别,但class_a.py中直接导入utils会失败,因为app目录不在搜索路径中。
最优解决方案(推荐)
统一使用基于项目根目录的绝对导入,也就是将app内部所有导入语句统一改为from app.utils import useful_function的形式,再分别适配两种运行场景即可,无需修改导入规则。
适配场景1:在app目录下正常运行script.py
不要直接用python script.py运行,回到项目根目录work下,用模块运行命令执行:
python -m app.script
-m参数会自动将当前工作目录(work)加入sys.path,同时将script.py作为包的模块运行,所有绝对导入均可正常识别。
适配场景2:在analysis.ipynb中正常导入app内组件
在notebook的第一个代码块最开头加入两行配置,将项目根目录加入搜索路径即可:
import sys, os # 若notebook存放在work目录下,写这行即可 sys.path.append(os.path.abspath('.')) # 若notebook存放在其他位置,替换为work目录的绝对路径,比如: # sys.path.append("/Users/xxx/Documents/work")
配置完成后再执行from app.class_a import MyClass就不会报错。
替代方案(无需修改运行命令)
如果不想每次运行script.py都切换目录加-m参数,可以在script.py的最开头加入路径配置:
import sys, os # 自动获取script.py所在目录的上层目录(即work目录),加入搜索路径 sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
配置完成后,不管在哪个目录下执行python script.py都能正常运行。
注意事项
不推荐使用from .utils import useful_function这类相对导入,当直接把Python文件作为脚本运行时(python xxx.py),Python会将该文件的__name__设置为__main__,相对导入会直接抛出错误,反而提高配置复杂度。
内容的提问来源于stack exchange,提问作者Boris Kalinin
相关产品推荐
相关产品推荐

