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 的第一个元素之后, 也就是加载的顺序不会优先于第一个元素的所在目录,但会在其他系统内置的目录之前 即会优先于系统内置定义的其他目录