Python 的绝对导入和相对导入
绝对导入需要包在 sys.path
中,可以通过环境变量 PYTHONPATH
来增加一些搜索路径。
相对导入需要当前在一个子包内。Relative imports in Python 3 - Stack Overflow 这个回答就说明如果直接运行一个包含了 import .xx
或者 from .xx import xx
的脚本就会失败,我的直观感受是这样的文件只能出现在比 main 文件(__name__
为 __main__
的那个文件,也就是入口文件)更深的文件夹下。相对导入有助于避免 sys.path 中出现更靠前的搜索路径,且该路径包含同名包,导致真正要导入的包被覆盖。
例子(什么时候相对导入会出错):
main.py
mypackage/
__init__.py
mymodule.py
myothermodule.py # from .mymodule import xx
直接运行 main.py 和 mymodule.py 都 OK,但是运行 myothermodule.py 则报错说没有 parent module。通过 python -m
来将文件视为一个模块运行,则可以将文件所在的文件夹作为 module 来运行,提供了 module 环境,但是该文件所在的文件夹并不会被加入 sys.path 中。
例子(直接运行脚本和视为模块运行的差异):
(tiny-llm-zh) ➜ tiny-llm-zh git:(main) ✗ tree test0
test0
├── __pycache__
│ └── test.cpython-310.pyc
└── test.py
2 directories, 2 files
(tiny-llm-zh) ➜ tiny-llm-zh git:(main) ✗ cat test0/test.py
import sys
print('\n'.join(sys.path))
(tiny-llm-zh) ➜ tiny-llm-zh git:(main) ✗ python test0/test.py
/home/xx/projects/tiny-llm-zh/test0
/home/xx/micromamba/envs/tiny-llm-zh/lib/python310.zip
/home/xx/micromamba/envs/tiny-llm-zh/lib/python3.10
/home/xx/micromamba/envs/tiny-llm-zh/lib/python3.10/lib-dynload
/home/xx/micromamba/envs/tiny-llm-zh/lib/python3.10/site-packages
(tiny-llm-zh) ➜ tiny-llm-zh git:(main) ✗ python -m test0.test
/home/xx/projects/tiny-llm-zh
/home/xx/micromamba/envs/tiny-llm-zh/lib/python310.zip
/home/xx/micromamba/envs/tiny-llm-zh/lib/python3.10
/home/xx/micromamba/envs/tiny-llm-zh/lib/python3.10/lib-dynload
/home/xx/micromamba/envs/tiny-llm-zh/lib/python3.10/site-packages
可以看到 python test0/test.py
将文件所在文件夹加入了 sys.path
,而 python -m test0.test
将 cwd(当前工作路径)加入了 sys.path
。