sys.path源码分析

Posted LynnTech

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sys.path源码分析相关的知识,希望对你有一定的参考价值。

先说sys.path初始化结果:

  1. *.pth定义的egg目录放在最前面;

  2. PYTHONPATH随后(如果定义了PYTHONPATH环境变量的话);

  3. pythonx.x.zip所在目录随后;

  4. prefix plat_linux2 lib_tk lib_old这些目录随后;

  5. lib-dynload的目录随后放进去;

  6. *.pth定义的其他目录放在最后;

  7. 预留了sitecustomize.py和usercustomize.py用户用户自定义一些行为。


这些path有两个模块构成:

  1. getpath.c的caculate_path计算module_search_path、prefix、exec_prefix全局变量;

  2. site.py用于将site-package目录本身和该目录下定义的*.pth文件中定义的目录(包括egg,其实egg也是一个目录,一个压缩的目录)放入sys.path中。


module_search_path、prefix、exec_prefix怎么来的?

都是由caculate_path这个函数计算出来。

  1. 首先计算出python可执行文件所在的目录,如果当前的可执行文件是一个软链接,里面会通过readlink找到最终的真正的可执行文件所在的目录,这个目录被赋值给变量argv0_path;

  2. 然后通过search_for_prefix从argv0_path一层层的上去找到包含landmark=lib/python2.7/os.py的目录,并将该目录(不包含os.py)赋值给prefix。

  3. 将prefix向上退两层,然后加上python27.zip,将其赋值给局部变量zip_path。

  4. 同计算prefix相同的逻辑,计算exec_prefix,只不过这时候landmark变成了lib/python2.7/lib-dynload。并赋值给exec_prefix。(getpath.c的注释中说道prefix放一些跨平台的代码;而exec_prefix放平台先关的代码或者二进制文件)。

  5. 然后就开始组合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函数中:

  1. 首先通过_PySys_Init初始化sys模块,此时已经计算出了三个变量,并将prefix、exec_prefix赋值给sys模块的prefix和exec_prefix;

  2. 后面有调用PySys_SetPath将module_search_path赋值给sys模块的path;

  3. 在然后通过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 有几种方式:

  1. 直接加入sys.path列表中;

  2. 将目录加入PYTHONPATH环境变量中,这种方式简单粗暴,容易引起不可预知的问题,比如其他地方也用到了这个环境变量;

  3. 将第三方库egg目录或者第三放库py目录加入.pth中

  4. 自定义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源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Mesos源码分析

Mybatis源码分析

Spring源码分析专题——目录

ARouter源码分析

Handler源码分析

Eureka源码分析(六) TimedSupervisorTask