python 加载模块的目录顺序

󰃭 2016-04-13

python的模块目录加载顺序

其加载顺序如下:

当前目录(代码的运行目录), PYTONPATH定义的目录,系统预定义的目录

验证场景

在path的内置模块中, 有一个test模块, 我们不管test的内容是什么, 自己实现一个这个模块test.py

#!/usr/bin/env python
#encoding=utf-8

test_name = "Yi_Zhi_Yu"

这是我们的test 模块(后面的代码默认不写开始两行的环境定义, 请自行补全) 我们再写一个c_test.py, 这个文件只是验证我们加载的test 是从哪里加载的

import test
print test

首先,我们将c_test.py 放置在test.py所在的目录, 运行

python c_test.py

可以看到

<module 'test' from '/home/tony/test/python/modules/test.pyc'>

可以看到这个是加载我们自己写的test模块, 如果不信, 可以自己验证test_name 变量

然后我们再把c_test.py 放置到我们的用户根目录 ~, 运行之

<module 'test' from '/usr/lib/python2.7/test/__init__.pyc'>

这里加载的是系统的test模块, 而不是我们自定义的test模块

由上我们看出, python 会优先在当前的目录查找对应的模块, 找不到的话才去系统目录里查找

但如果我们指定了PYTHONPATH这个环境变量到我们自己的test模块, 用户目录下的c_test.py 会打印什么呢

PYTHONPATH=/home/tony/test/python/modules/ python ~/c_test.py

结果:

<module 'test' from '/home/tony/test/python/modules/test.pyc'>

可以看到打印的是我们自定义的test模块,而非系统内置的test 模块

到这里可以说明, PYTHONPATH定义的路径要优于系统内置的模块加载路径

我们再将我们自定义的test.py copy 到用户根目录下, 这样我们就有两个自定义的test 模块了, 虽然内容一样。

然后我们执行

PYTHONPATH=/home/tony/test/python/modules/ python ~/c_test.py

结果是

<module 'test' from '/home/tony/test.py'>

加载的是我们新的自定义的test模块,而不是老的自定义的test模块

到这里可以说明, python的代码的工作目录的模块加载要优于PYTHONPATH指定的目录模块

到这里可以确定, python的模块加载顺序正如开始我们说明的

当前目录(代码的运行目录), PYTONPATH定义的目录,系统预定义的目录

那么系统预定义的模块加载的目录在哪里呢 在c_test.py 修改一下, 如下

#import test
import sys

#print test
print sys.path #这里打印的就是内置的模块加载目录

运行

['/home/tony', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client']

以上就是python 回去寻找模块的路径, 这里是内置的, 是个list, 注意, 这个list的第一个路径永远都是我们的代码的运行目录, 把c_test.py copy 到/tmp 运行, 第一个就变成了/tmp

再用指定PYTHONPATH的方式执行

PYTHONPATH=/home/tony/test/python/modules/ python ~/c_test.py

结果如下

['/home/tony', '/home/tony/test/python/modules', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client']

可以看到, 第二个元素变成了PYTHONPATH 中指定的目录

至此,我们可以看出, 无论怎么修改加载目录, python模块的加载都是从sys.path目录依次查找的

总结

python模块的加载目录是从sys.path里定义的目录依次查找的,

然而我们可以通过PYTHONPATH 对其进行有限的控制,

为何是有限, 因为定义的PYTHONPATH 总是在 sys.path 的第一个元素之后, 也就是加载的顺序不会优先于第一个元素的所在目录,但会在其他系统内置的目录之前 即会优先于系统内置定义的其他目录