【Python常见问题】【路径】路径总是有问题?深度剖析
一、什么是“路径”?
- 路径,指的是Python在“找模块”时,到哪里去找。
- 这些路径都存在一个叫sys.path的列表里。你可以在Python里打印出来看看
import sysprint(sys.path)
二、Python找模块的顺序
- 当前脚本所在目录(你运行的那个.py文件的目录)
- 环境变量PYTHONPATH里设置的目录
- 标准库目录(比如你装Python时自带的库)
- site-packages(你用pip装的第三方库)
a.当前脚本所在目录
指的是你运行的那个.py文件所在的目录(不是被import的文件)
例如:
- 在/home/user/project/目录下运行python src/main.py,那么“当前目录”就是/home/user/project/src/。
- 在/home/user/project/目录下运行python -m src.main,那么“当前目录”就是/home/user/project/。
- 这个目录会被自动加到sys.path的第一个位置。
b.环境变量PYTHONPATH
可以通过设置环境变量PYTHONPATH,让Python在import模块时,额外去你指定的目录里找。
例如:
- Windows下:set PYTHONPATH=E:\my_libs
- Linux/macOS下:export PYTHONPATH=/home/user/my_libs
这样你就可以importmy_libs目录下的模块了。
PYTHONPATH里的目录会被加到sys.path的前面(在标准库之前)。
c.标准库目录
Python自带的库,比如os、sys、json等。
这些库一般在你安装Python的目录下,比如C:\Python39\Lib或者/usr/lib/python3.9/。
这些目录在sys.path的后面。
d.site-packages
这是你用pip install安装的第三方库的存放目录。
一般在C:\Python39\Lib\site-packages或者/usr/local/lib/python3.9/site-packages/。
也在sys.path的后面,和标准库目录一起。
e.sys.path的顺序(举例)
假设你在E:\project目录下运行:
set PYTHONPATH=E:\my_libs
python src/main.py
此时sys.path大致如下(顺序很重要):
- E:\project\src(当前脚本目录)
- E:\my_libs(PYTHONPATH)
- C:\Python39\Lib(标准库)
- C:\Python39\Lib\site-packages(第三方库)
f.查找流程
当你写import xxx时,Python会按照sys.path的顺序,依次在每个目录下找有没有叫xxx.py或xxx包的文件夹,找到就用,找不到就继续下一个目录,直到找完所有目录。如果都找不到,就报ModuleNotFoundError。
三、项目中的单个文件的路径
你运行的那个.py文件所在的目录会被自动加到sys.path的第一个位置。
比如,当我把test.py放置在images下
此时的sys.path就会自动把test.py的父目录加到sys.path的第一个位置,如下图
当我把test.py放置在src下
此时的sys.path就会自动把test.py的父目录即src加到sys.path的第一个位置,如下图
四、运行路径与导入路径
当你在项目根目录下直接运行:python src/main.py
而在main.py中有类似于:from src.xxx import xxx 或者 from .xxx import xxx 就会出现“没有src模块”或“attempted relative import with no known parent package”等问题。
如果你的项目结果如下:
xxx/
├── src/
│ └── main.py
└── 其他文件...
此时sys.path的第一个元素是xxx/src,而不是xxx
当在main.py中写 from src.datasets import dataset 时,python会去 src/src/datasets 下找,找不到就会报错
五、推荐做法
1.用 -m 参数
python -m src.main
解释 src.main 和 src/main 的区别
src.main
- 这是包名.模块名的写法。
- src是包,main是src包下的main.py模块。
- Python会自动去src目录下找main.py,并把src当作包来处理。
- 这样包内的相对导入、绝对导入都能正常工作。
src/main(斜杠分隔)
- 这是文件路径的写法,操作系统用来定位文件。
- 不能用在python -m后面。
- 如果你写python -m src/main,Python会报错,因为它只认包名和模块名的点号分隔方式。
2.设置PYTHONPATH
在根目录下运行:
set PYTHONPATH=.
python src/main.py
这样,(根目录)会被加到sys.path前面,也能找到src包。