首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

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

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180322G1RKWE00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券