python导入本地库文件
python导入本地库文件
问题背景
在导入一个开源的gitbub项目的师傅,报错发现没有对应的目录,于是去网上找到对应的解决办法,现在做个总结
python包路径搜索机制
在解决问题前,我们先来了解一下问题的原因,可以用
- 来查询当前已安装的包
1 | pip list package_name |
- 在python解释器里使用sys.path
1 | import sys |
sys.path其实就是你的python解释器真正搜索包路径的顺序
python的sys.path解释
sys.path 的第一个路径是脚本的执行目录,如果启动的是交互式python解释器(也就是直接在命令行启动python;或者脚本是从标准输入获取的,则这第一个路径是一个空字符串’’)
第三方库
1
/usr/lib/python3/site-packages:/home/user/.local/lib/python3/site-packages
PYTHONPATH环境变量
大部分老手都知道将自己的一些模块路径打入系统环境变量中,让python解释器能够找到
1
export PYTHONPATH=$PYTHONPATH:/path/to/my/module
各个路径下的
.pth
文件,每行一个路径这个也是最近刚搞明白的。python包的安装有一种是从本地的仓库安装
1
2
3git clone url/to/git/repository.git
cd repository
pip install -e .这样安装的包叫做可编辑包,路径依旧是放置在原始路径下。一开始我很奇怪,这样安装python解释器里面的sys.path如何有这个路径的。后来才发现,这个路径被写入了
/home/$USER/.local/lib/python3/site-packages/easy-install.pth
里面 。同时,在.pth的同级目录下,会有一个xxx.egg-info文件,里面只有一行,也就是标识了包的路径,与在easy-install.pth里的路径一样。用pip uninstall xxx的时候,会把xxx.egg-info删除
python从哪里找到 .pth 文件
之前在网上看到有人说python解释器启动的时候会载入在sys.path列表下所有目录中下面以.pth结尾的文件。然而,这是个大坑!!!python根本不会这样做。百般寻找终于找到官方说明:site – 指定域的配置钩子 - Python 3.10.1 文档
site.py 包
site – 站点专属的配置钩子 - Python 3.8.12 文档
python解释器在启动的过程中会载入site包,并从中拿到要去检索的路径,将那些路径下的.pth结尾的文件,里面一行一行的路径加载入sys.path列表下,去除了不存在的路径。(.pth文件下面每一行是一个路径)
那么site包会提供哪些检索路径?
根据官方文档,site包会将sys.prefix和sys.exec_prefix作为头部,将lib/pythonX.Y/site-packages
(On Unix and macOS),lib/site-packages
(On Windows)作为尾部进行拼接,对于每个拼接后唯一的目录,会在该目录下搜索pth文件,并将pth文件内的路径载入sys.path. 使用 site.getsitepackages
()可以获取所有的搜索路径
1 | import site |
然而,坑爹的地方来了!!Debian的发行版的python跟原生的python是不一样的!!!也就是说,以Ubuntu系统为例,通过Ubuntu的包管理器apt / apt-get
安装的python和从源码编译的python是不完全一样的。 https://wiki.debian.org/Python 这里面说明了不一样的地方
dist-packages instead ofsite-packages. Third party Python software installed from Debian packages goes intodist-packages
What’s the difference between dist-packages and site-packages?
其实似乎还有更多不一样的地方。
实际上,查看site.py(Debian分支)的源码,可以找到site.getsitepackages
()方法部分源码
1 | if os.sep == '/': |
也就是说,实际上是这样的:
1 | >>> python -c "import site; print(site.getsitepackages())" |
而python的官方库里面,这段代码(https://github.com/python/cpython/blob/7c5b01b5101923fc38274c491bd55239ee9f0416/Lib/site.py#L319)是这样的:
1 | def getsitepackages(prefixes=None): |
除了以上的路径之外,还会到用户路径下搜索pth文件
对于Unix系统,会到路径:~/.local/lib/pythonX.Y/site-packages
下搜索 。可以用site.getusersitepackages
()方法获取这个路径
1 | >>> python -c "import site; print(site.getusersitepackages())" |
坑爹的地方
- 被网上不靠谱的地方误导:网上很多帖子都说python会到所有的sys.path下的路径搜索pth文件,有些说加入PYTHONPATH的路径下的pth文件也会被检索到
- Debian的python和pip跟原生的有些区别。更具体来说用源码编译的python,会将
pip install -e .
的包安装到xxx/site-packages下(虽然这些路径在编译python的时候是可以设置的),而通过debian(比如Ubuntu)的包管理器(apt)安装的python,会将pip install -e .
的包安装到xxx/dist-packages下
python导入包报错的解决办法
1 | import sys |