Python跨目录导入模块失败如何正确解决?
首先咱们先明确你的目录结构(方便对照):
some_root/ - __init__.py - dir_0/ - __init__.py - dir_1/ - __init__.py - file_1.py - dir_2/ - __init__.py - file_2.py
你遇到的导入失败,本质是Python的模块搜索路径不包含some_root目录——当你直接运行file_2.py时,Python只会把dir_2(当前脚本所在目录)加入搜索路径,找不到上层的dir_0包。下面是几种靠谱的解决办法:
方案1:以包的形式运行脚本(推荐,无需修改代码)
这是最符合Python包规范的做法,不用改任何导入代码,只要调整运行方式:
- 打开终端,切换到
some_root的父目录(也就是包含some_root的那个目录) - 用
-m参数以模块方式运行file_2.py:
python -m some_root.dir_0.dir_2.file_2
这样Python会自动把some_root目录加入模块搜索路径,你原来写的绝对导入from dir_0.dir_1.file_1 import foo就能正常工作了。
注意:所有目录下的
__init__.py可以是空文件,只要存在就行——它的作用是告诉Python这是一个可导入的包目录。
方案2:使用相对导入(需以包形式运行)
如果你想用相对路径来导入,修改file_2.py的导入语句:
# file_2.py from ..dir_1.file_1 import foo
这里的..表示当前目录(dir_2)的上一级目录(dir_0),然后就能找到dir_1/file_1.py了。
但要注意:相对导入不能直接运行脚本,你还是得按照方案1的方式,在some_root的父目录下用python -m some_root.dir_0.dir_2.file_2来运行,不然会报错attempted relative import with no known parent package。
方案3:临时添加sys.path(万不得已时用)
如果因为某些原因,你必须直接运行file_2.py(比如不能用-m参数),可以临时把some_root目录加入Python的搜索路径。修改file_2.py:
# file_2.py import sys from pathlib import Path # 获取some_root目录的绝对路径 some_root_path = Path(__file__).parent.parent.parent sys.path.append(str(some_root_path)) # 现在就能正常导入了 from dir_0.dir_1.file_1 import foo
解释一下:Path(__file__)是当前file_2.py的绝对路径,.parent三次后就拿到了some_root目录的路径,把它加入sys.path后,Python就能找到dir_0包了。
提醒:这种方法不够优雅,因为代码依赖目录结构——如果以后目录层级变了,你就得修改这段路径代码,所以优先用前两种方案。
内容的提问来源于stack exchange,提问作者Aarni Joensuu

