sys.path源码分析
Posted LynnTech
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sys.path源码分析相关的知识,希望对你有一定的参考价值。
先说sys.path初始化结果:
*.pth定义的egg目录放在最前面;
PYTHONPATH随后(如果定义了PYTHONPATH环境变量的话);
pythonx.x.zip所在目录随后;
prefix plat_linux2 lib_tk lib_old这些目录随后;
lib-dynload的目录随后放进去;
*.pth定义的其他目录放在最后;
预留了sitecustomize.py和usercustomize.py用户用户自定义一些行为。
这些path有两个模块构成:
getpath.c的caculate_path计算module_search_path、prefix、exec_prefix全局变量;
site.py用于将site-package目录本身和该目录下定义的*.pth文件中定义的目录(包括egg,其实egg也是一个目录,一个压缩的目录)放入sys.path中。
module_search_path、prefix、exec_prefix怎么来的?
都是由caculate_path这个函数计算出来。
首先计算出python可执行文件所在的目录,如果当前的可执行文件是一个软链接,里面会通过readlink找到最终的真正的可执行文件所在的目录,这个目录被赋值给变量argv0_path;
然后通过search_for_prefix从argv0_path一层层的上去找到包含landmark=lib/python2.7/os.py的目录,并将该目录(不包含os.py)赋值给prefix。
将prefix向上退两层,然后加上python27.zip,将其赋值给局部变量zip_path。
同计算prefix相同的逻辑,计算exec_prefix,只不过这时候landmark变成了lib/python2.7/lib-dynload。并赋值给exec_prefix。(getpath.c的注释中说道prefix放一些跨平台的代码;而exec_prefix放平台先关的代码或者二进制文件)。
然后就开始组合module_search_path了:
如果定义了PYTHONPATH,放进去;
zip_path放进去;
通过prefix+defpath(=:plat_linux2:lib_tk:lib_old)找到这些目录的全路径放进去,由于第一个是空的,所以会把prefix也放进去;
把exec_prefix放进去。
site-package怎么放进去的?
site.py中,有个addsitedir函数,该函数将读取site-package中的pth文件内容,并将该内容一行行的加入sys.path中,如果该行以import开头,则执行。
而将egg放在sys.path的前面就是pth文件中,用import开头来做的。
计算出来的三个全局变量什么时候加入到sys.path中?
在pythonrun.c中的Py_InitializeEx函数中:
首先通过_PySys_Init初始化sys模块,此时已经计算出了三个变量,并将prefix、exec_prefix赋值给sys模块的prefix和exec_prefix;
后面有调用PySys_SetPath将module_search_path赋值给sys模块的path;
在然后通过initsite初始化site.py模块,由于该模块里有main的调用,因此import site模块会自动计算site-package相关环境,并进一步加入sys.path中。
dist-package、site-package有什么区别?
dist-package可能存在两个:
/usr/lib/pythonx.x/dist-packages。利用debian包管理器安装的python第三方库会放入这里;
/usr/local/lib/pythonx.x/dist-packages。由于pip、easy_install这些工具也是用debian包管理安装的,所以通过这些工具安装的第三方库放在这里;
site-package只存在与自己源码编译的python版本中:
比如在我的电脑上由于用了默认路径,就存在/usr/local/lib/pythonx.x/site-packages/。通过自己编译的python安装的第三方库都放在该目录中。
搞这些是因为做好兼容,防止第三方库由于python版本不同而导致的不兼容。因此,如果你用系统自带的python安装了很多第三库,然后又自己编译了python,就要重新安装这些第三方库。可以通过一些技巧公共部分第三方库(比如修改pth),但是不建议这样搞,因此这样做并不能保证兼容性。
如何修改sys.path?
修改syspath 有几种方式:
直接加入sys.path列表中;
将目录加入PYTHONPATH环境变量中,这种方式简单粗暴,容易引起不可预知的问题,比如其他地方也用到了这个环境变量;
将第三方库egg目录或者第三放库py目录加入.pth中
自定义sitecustomize.py和usercustomize.py文件。
参考:
http://mikeboers.com/blog/2014/05/23/where-does-the-sys-path-start
https://stackoverflow.com/questions/9387928/whats-the-difference-between-dist-packages-and-site-packages
以上是关于sys.path源码分析的主要内容,如果未能解决你的问题,请参考以下文章