python模块搜索路径_Python 的模块搜索路径

一种语言要使用到外部库(模块) 时必然会涉及到从哪里以及按何顺序加载依赖,就像 LD_LIBRARY_PATH, CLASSPATH 那样,Python 也有其默认的模块搜索顺序, 依序找到想要的模块即停止。Python 中 sys.path 返回的列表包含了模块搜索的顺序,我们可以程序中修改该列表,或用 PYTHONPATH 环境变量前插路径,甚至是用  .pth 文件来附加路径。

简单的,可以执行命令 python3 -c "import sys; print(str(sys.path).replace(',', '\n'))" 来查看 python3 交互 shell 下的模块搜索路径,类似结果如下:

[''

'/usr/lib/python36.zip'

'/usr/lib/python3.6'

'/usr/lib/python3.6/lib-dynload'

'/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']

注意,第一个元素是个空字符串,代表进入 python3 shell 时的当前目录。

如果在通过一个 py 脚本文件来打印 sys.path 的话显示稍微有所差异。比如在目录 /home/yanbin/Developers/ 下创建 test.py 文件,内容为

1

2

3

4

importsys

forlineinsys.path:

print(f"'{line}'")

而我们退到 /home/yanbin 为当前目录来执行 python3 Developers/test.py, 显示出来的搜索路径如下:

'/home/yanbin/Developers'

'/usr/lib/python36.zip'

'/usr/lib/python3.6'

'/usr/lib/python3.6/lib-dynload'

'/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'

第一行的路径有所不同了,变成了一个绝对路径,也就是说 test.py 可以从它所在目录上加载模块。比如在  /home/yanbin/Developers 下有 mymath.py, 在 test.py 中能够直接 import mymath 成功。但是把  mymath.py 放到当前目录 /home/yanbin 下就加载不到了。除非用 PYTHONPATH 指定当前目录 ., 后面会讲到。

再次重复一下 Python shell 与执行脚本文件时,模块搜索路径第一个路径显示方式不一样,Python shell 下用空字符串表示进行 shell 时的当前目录,执行脚本时第一个路径是脚本文件所在的目录。Shell 启动时目录或脚本所以在目录总是最高优先级的模块搜索路径。

接下来介绍如何动态修改 sys.path 以及用环境变量 PYTHONPATH 如何影响 sys.path 来增加新的搜索路径。至于用 .pth 文件附加路径的方式后面会另立新篇。

动态修改 sys.path

sys.path 是一个可变的列表,所以运行时可以随便修改它的内容,比如说想要加载 /home/yanbin/test 下的  mymath 模块,但是它没出现在  sys.path 列表中,我们可以这样做

1

2

3

4

5

importsys

sys.path.append('/home/yanbin/test')

importmymath

print(mymath.pi)

这只是一条路子,程序中不应该经常性的这么做,因为 sys.path 是一个全局变量,如果运行时想改就改,最终不知道模块是从哪儿加载过来的。相比,下面的 PYTHONPATH 比较实用些。

理解 Python 的模块路径有助于理解 Python 的依赖管理工具的实现原理,像  easy_install, pip, pipenv, virtualenv 等,它们通过各种途径最终修改最终影响到 sys.path 列表。它们在还会使用 .pth 文件来进一步增强 sys.path 列表。

PYTHONPATH 环境变量向前添加模块搜索路径

如果用环境变量 PYTHONPATH 设置了模块搜索路径,它的内容将被向前添加到 sys.path 列表中去,准确来讲是插入到 sys.path 的第一个元素后面。PYTHONPATH 中可以使用绝对路径和相对路径,相对路径是相对于 Shell 启动时的目录或脚本文件所在的目录。

举例来看

python shell

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

$exportPYTHONPATH=/home/yanbin/test:extra_modules

$cd/

$python3

>>>importsys

>>>forlineinsys.path:

...print(f"'{line}'")

...

''

'/home/yanbin/test'

'/extra_modules'

'/usr/lib/python36.zip'

'/usr/lib/python3.6'

'/usr/lib/python3.6/lib-dynload'

'/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'

看到相对路径 extra_modules 相对于进入 shell 前的  / 目录,效果上相当于

1

sys.path[1:1]=['/home/yanbin/test','/extra_modules']

脚本文件的方式

这一次我们在 PYTHONPATH 中把当前路径给加上

1

2

3

$exportPYTHONPATH=.:/home/yanbin/test:extra_modules

$cd/home/yanbin

$python3Developers/test.py

输出如下

1

2

3

4

5

6

7

8

9

10

11

'/home/yanbin/Developers'

'/home/yanbin'

'/home/yanbin/test'

'/home/yanbin/extra_modules'

'/usr/lib/python36.zip'

'/usr/lib/python3.6'

'/usr/lib/python3.6/lib-dynload'

'/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'

第一行为脚本文件所在的目录,/home/yanbin 为 PYTHONPATH 中的  .。这样我们既能够从脚本所在的目录,也可以从当前工作目录中加载模块了,惊喜就是 cd 切换一下目录后代码就可能不工作了。

小结:

sys.path 能列出模块搜索顺序,Python REPL 中第一个路径为空字符串,代表 Shell 启动时的目录,执行脚本文件时第一个路径是脚本文件所在的目录

PYTHONPATH 环境变量可以使用绝对和相对路径。相对路径相对于 Shell 启动时目录或程序脚本文件所在目录

PYTHONPATH 中的所有路径会以 sys.path[1:1] =  的方式添加到 sys.path 搜索路径列表中

动态的改动 sys.path 自己应该尽量少用吧,依赖管理工具除外

可由此理解依赖管理工具,如 easy_install,pip, pipenv, 和 virtualenv 是如何工作的,最终的搜索路径是由 sys.path 决定的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值