用 .pth 文件附加 Python 模块搜索路径

上一篇 Python 的模块搜索路径,介绍了 Python 的模块搜索路径,最终起作用的是 sys.path 路径列表。如果要自定义自己的搜索路径,就是要怎么定制 sys.path 的内容。可以简单的用 PYTHONPATH 环境变量前向添加,这儿将要说的是用 .pth 文件的方式。也可由此进一步理解 Python 依赖管理工具,像  virtualenv 等的工作原理。

.pth 文件名是什么,无所谓,Python 只认扩展名。.pth 文件中每行指定一个路径 -- 绝对或相对路径(相对于本  .pth 文件所在的目录),另外还可以空行或 # 开始的注释行,还能有 import 语句,大概只用来校验是否能导入成功,程序代码中还是需要显示的 import 模块。

.pth 文件放在哪里

.pth 文件创建好后应该放到哪里去呢?不是 sys.prefix 指示的位置,也不是 sys.path 中任意一个目录,而是  sys.path 中属于 site.packages 的某一个目录中。可以用

>>> import site
>>> site.getusersitepackages()
>>> site.getsitepackages()

查看到, 看我在  Ubuntu Linux 中看到的内容(为便于阅读,显示列表内容时进行了换行处理)

从上面看到  sys.path 包含了 site.getusersitepackages() 和 site.getsitepackages() 的内容,并且 site.getusersitepackages() 在前

'/home/yanbin/.local/lib/python3.6/site-packages',
'/usr/local/lib/python3.6/dist-packages',
'/usr/lib/python3/dist-packages',
'/usr/lib/python3.6/dist-packages'

而我们的  .pth 文件就可以放到以上四个目录中的任意位置,也可以放置多个 .pth 文件,选择那个目录,一个是搜索的先后顺序,还有就是 .pth 中的相对目录会相对于 .pth 所在的位置。

如果是不考虑多用户共享的情况,并且操作不用 sudo 前缀,我们就把 .pth 文件放到 usersitepackages() 指示的目录下,即 /home/yanbin/.local/lib/python3.6/site-packages。该目录还能直接用如下命令获得得

python3 -m site --user-site
/home/yanbin/.local/lib/python3.6/site-packages

在此位置上创建一个文件,命名为 example.pth, 内容如下

第一行用的绝对目录,第二行为相对目录,相对于 example.pth 所在的目录 /home/yanbin/.local/lib/python3.6/site-packages。假如以上两个目录

/home/program/mymath
/home/yanbin/.local/lib/python3.6/site-packages/mymodules

都存在的话,进到 Python3 Shell, 再次查看 sys.path 的内容就变成了

留意上面的顺序,.pth 放在哪个目录下,它所增加的路径就会跟随在那个 site-packages 后面。效果上相当于

pos = sys.path.index('/home/yanbin/.local/lib/python3.6/site-packages')
sys.path[pos:pos] = ['home/program/mymath', '/home/yanbin/.local/lib/python3.6/site-packages/mymodules']

如果 example.pth 文件放在 /usr/lib/python3/dist-packages 目录中,那么添加的两个路径也就跟在它后面,并且相对路径也是相对它。

Python 会话启动时会对 .pth 中配置的目录存在性进行检测,如果 example.pth 中配置的 /home/program/mymath 不存在,那么 /home/program/mymath 将不会出现在  sys.path 列表中, 相对路径也是如此。

.pth 文件中 import 的作用

再来稍微探讨一下在 .pth 文件中 import 语句的作用,.pth 中除了空行,注释行和目录外,只能有  import 开头的语句。实践中试验了一下,在  .pth 中写上一句

import mymath

并不意味着在程序代码中就能直接用 mymath 模块了,若直接 mymath.pi 使用 mymath 中的属性或方法是会收到

NameErro: name 'mymath' is not defined

的错误,因此尽管在  example.pth 中有  import mymath, 在程序代码中欲使用 mymath 模块的话还必须加上同样的 import mymath

好像  .pth 中的 import mymath 语句没什么用,却又并不属实。比如说在  .pth 中 import mymathxx 不存在的模块,在进入  Python3  会话时就会收到一个错误

➜ ~ python3
Error processing line 4 of /home/yanbin/.local/lib/python3.6/site-packages/example.pth:

Traceback (most recent call last):
File "/usr/lib/python3.6/site.py", line 174, in addpackage
exec(line)
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'mymathxx'

Remainder of file ignored

不能加载到模块  mymathxx, 并且 import mymathxx 后的内容被忽略掉,仍能进入 Python3 的  Shell。

所以粗略的感觉 .pth 中的 import  的语句只是用来校验想要加载的模块是否真的存在。当有任何欲加载的模块不能导入的话应当给予重视。

pipenv 和 virtualenv 中的路径初探

pipenv 和  virtualenv 环境中的 site 没有了  site.getsitepackages() 和 site.getusersitepackages()  这两个方法了。

pipenv

pipenv shell ,然后再进入  python3 或者用  pipenv run python3 main.py 来查看 sys.path 的内容,类似如下:

virtualenv

如果是一个  virtualenv 项目的话,它目录下有自己独套班子,bin, include, lib 目录,bin 下有自己的  python3, pip3 等命令。执行项目自己的  python3 查看 sys.path 内容大致如下:

几乎所有的依赖都能在项目目录下找到(除  /usr/lib/python3.6 外),不用跑到用户目录或  Python 公共的  site-packages 目录去找。因此 virtualenv 项目才是一个独立可部署的,打包,拷贝,解压后运行自己的 bin/Python3 命令即可。

链接:

  1. Site-specific configuration hook
  2. 10.9 将文件夹加入到sys.pth
  3. Python 中 pth 文件的使用
  4. Pipenv & Virtual Environments
  5. Site-wide configuration

本文链接 https://yanbin.blog/pth-file-append-python-module-search-path/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

4 Comments
Inline Feedbacks
View all comments
trackback

[…] 用 .pth 文件附加 Python 模块搜索路径 | 隔叶黄莺 Yanbin Blog - 软件编程实践 […]

trackback

[…] 用 .pth 文件附加 Python 模块搜索路径 | 隔叶黄莺 Yanbin Blog - 软件编程实践 […]

trackback

[…] 用 .pth 文件附加 Python 模块搜索路径 | 隔叶黄莺 Yanbin Blog – 软件编程实践 […]

trackback

[…]  /Users/yanbin/my-package 见 用 .pth 文件附加 Python 模块搜索路径 […]