Python: lib/site-packages/site.py和lib/site.py之间的相互作用

11

由于一个特定的问题(问题),我花了大部分时间来研究site.py(s)的工作方式。但其中有一点我不理解。

据我所知,当python被加载时,首先会运行 lib/python2.7/site-packages/site.py,它会检查 PYTHONPATH,查找 lib/python2.7/site.py 并将其导入。该文件具有 addsitedir 方法,不仅将路径添加到 sys.path 中,而且还会处理其中存在的 *.pth 文件。此时,会运行来自 lib/python2.7/site.pymain(),并在 site-packages 和 user-site-packages 上运行 addsitedir

现在进入奇怪的部分。现在我们回到 lib/python2.7/site-packages/site.py,它会遍历 pythonpath 中的每个路径,并在其中运行 addsitedir。我发现这很奇怪,原因有二:

  1. addsitedir 会在 lib/python2.7/site-packages 上运行两次。
  2. 这本身并不算太糟糕(不能将任何内容两次添加到 sys.path 中),但是似乎 lib/python2.7/site.py 有一种机制允许雄心勃勃的用户通过实现 usercustomize 模块来操纵 sys.path(嘿,这甚至在文档中提到)。显然,当你实现这样一个机制时,你希望确保用户最后才进入,这样他就能控制添加到 sys.path 的所有内容。但是这在这里不是这样的情况(我很沮丧地发现)。很可能,第二次调用 lib/python2.7/site-packages 将覆盖 usercustomize 所做的所有工作。

我知道这很糟糕,但我向 addsitedir 添加了一个打印语句,打印它接收的路径,以便说明发生了什么。这些是处理的路径:

/home/user/.local/lib/python2.7/site-packages #lib/python2.7/site.py
/home/user/py/lib/python2.7/site-packages     #lib/python2.7/site.py
#This is where your usercustomize runs
#Followin calls are from lib/python2.7/site-packages/site.py
/home/user/py/lib/python2.7/site-packages/numpy-1.9.0-py2.7-linux-x86_64.egg
/home/user/Develop/Python/myproject
/home/user/lmfit-0.7.2
/home/user/py/lib/python2.7/site-packages #NOTE: this runs a second time

那么我在这里询问什么呢?

A. 我希望能了解为什么需要第二次调用site-packages。

B. 考虑到该实现,usercustomize是否像我认为的那样受到限制?那么,你会如何实现从sys.path中“删除”路径(从理论上来说)的功能?


请求的调试输出:

:genie39:~ ;-) python2.7 -v
# installing zipimport hook
import zipimport # builtin
# installed zipimport hook
# /home/user/py/lib/python2.7/site-packages/site.pyc matches /home/user/py/lib/python2.7/site-packages/site.py
import site # precompiled from /home/user/py/lib/python2.7/site-packages/site.pyc
# /home/user/py/lib/python2.7/os.pyc matches /home/user/py/lib/python2.7/os.py
import os # precompiled from /home/user/py/lib/python2.7/os.pyc
import errno # builtin
import posix # builtin
# /home/user/py/lib/python2.7/posixpath.pyc matches /home/user/py/lib/python2.7/posixpath.py
import posixpath # precompiled from /home/user/py/lib/python2.7/posixpath.pyc
# /home/user/py/lib/python2.7/stat.pyc matches /home/user/py/lib/python2.7/stat.py
import stat # precompiled from /home/user/py/lib/python2.7/stat.pyc
# /home/user/py/lib/python2.7/genericpath.pyc matches /home/user/py/lib/python2.7/genericpath.py
import genericpath # precompiled from /home/user/py/lib/python2.7/genericpath.pyc
# /home/user/py/lib/python2.7/warnings.pyc matches /home/user/py/lib/python2.7/warnings.py
import warnings # precompiled from /home/user/py/lib/python2.7/warnings.pyc
# /home/user/py/lib/python2.7/linecache.pyc matches /home/user/py/lib/python2.7/linecache.py
import linecache # precompiled from /home/user/py/lib/python2.7/linecache.pyc
# /home/user/py/lib/python2.7/types.pyc matches /home/user/py/lib/python2.7/types.py
import types # precompiled from /home/user/py/lib/python2.7/types.pyc
# /home/user/py/lib/python2.7/UserDict.pyc matches /home/user/py/lib/python2.7/UserDict.py
import UserDict # precompiled from /home/user/py/lib/python2.7/UserDict.pyc
# /home/user/py/lib/python2.7/_abcoll.pyc matches /home/user/py/lib/python2.7/_abcoll.py
import _abcoll # precompiled from /home/user/py/lib/python2.7/_abcoll.pyc
# /home/user/py/lib/python2.7/abc.pyc matches /home/user/py/lib/python2.7/abc.py
import abc # precompiled from /home/user/py/lib/python2.7/abc.pyc
# /home/user/py/lib/python2.7/_weakrefset.pyc matches /home/user/py/lib/python2.7/_weakrefset.py
import _weakrefset # precompiled from /home/user/py/lib/python2.7/_weakrefset.pyc
import _weakref # builtin
# /home/user/py/lib/python2.7/copy_reg.pyc matches /home/user/py/lib/python2.7/copy_reg.py
import copy_reg # precompiled from /home/user/py/lib/python2.7/copy_reg.pyc
import imp # builtin
# /home/user/py/lib/python2.7/site.pyc matches /home/user/py/lib/python2.7/site.py
import site # precompiled from /home/user/py/lib/python2.7/site.pyc
# /home/user/py/lib/python2.7/traceback.pyc matches /home/user/py/lib/python2.7/traceback.py
import traceback # precompiled from /home/user/py/lib/python2.7/traceback.pyc
# /home/user/py/lib/python2.7/sysconfig.pyc matches /home/user/py/lib/python2.7/sysconfig.py
import sysconfig # precompiled from /home/user/py/lib/python2.7/sysconfig.pyc
# /home/user/py/lib/python2.7/re.pyc matches /home/user/py/lib/python2.7/re.py
import re # precompiled from /home/user/py/lib/python2.7/re.pyc
# /home/user/py/lib/python2.7/sre_compile.pyc matches /home/user/py/lib/python2.7/sre_compile.py
import sre_compile # precompiled from /home/user/py/lib/python2.7/sre_compile.pyc
import _sre # builtin
# /home/user/py/lib/python2.7/sre_parse.pyc matches /home/user/py/lib/python2.7/sre_parse.py
import sre_parse # precompiled from /home/user/py/lib/python2.7/sre_parse.pyc
# /home/user/py/lib/python2.7/sre_constants.pyc matches /home/user/py/lib/python2.7/sre_constants.py
import sre_constants # precompiled from /home/user/py/lib/python2.7/sre_constants.pyc
# /home/user/py/lib/python2.7/_sysconfigdata.pyc matches /home/user/py/lib/python2.7/_sysconfigdata.py
import _sysconfigdata # precompiled from /home/user/py/lib/python2.7/_sysconfigdata.pyc
# zipimport: found 604 names in /home/user/py/lib/python2.7/site-packages/pytz-2014.7-py2.7.egg
# zipimport: found 20 names in /home/user/py/lib/python2.7/site-packages/hashlib-20081119-py2.7-linux-x86_64.egg
# zipimport: found 40 names in /home/user/py/lib/python2.7/site-packages/pysqlite-2.6.3-py2.7-linux-x86_64.egg
# zipimport: found 7 names in /home/user/py/lib/python2.7/site-packages/mock-1.0.1-py2.7.egg
import encodings # directory /home/user/py/lib/python2.7/encodings
# /home/user/py/lib/python2.7/encodings/__init__.pyc matches /home/user/py/lib/python2.7/encodings/__init__.py
import encodings # precompiled from /home/user/py/lib/python2.7/encodings/__init__.pyc
# /home/user/py/lib/python2.7/codecs.pyc matches /home/user/py/lib/python2.7/codecs.py
import codecs # precompiled from /home/user/py/lib/python2.7/codecs.pyc
import _codecs # builtin
# /home/user/py/lib/python2.7/encodings/aliases.pyc matches /home/user/py/lib/python2.7/encodings/aliases.py
import encodings.aliases # precompiled from /home/user/py/lib/python2.7/encodings/aliases.pyc
# /home/user/py/lib/python2.7/encodings/utf_8.pyc matches /home/user/py/lib/python2.7/encodings/utf_8.py
import encodings.utf_8 # precompiled from /home/user/py/lib/python2.7/encodings/utf_8.pyc
Python 2.7.8 (default, Sep  7 2014, 12:14:33) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
dlopen("/home/user/py/lib/python2.7/site-packages/readline-6.2.4.1-py2.7-linux-x86_64.egg/readline.so", 2);
import readline # dynamically loaded from /home/user/py/lib/python2.7/site-packages/readline-6.2.4.1-py2.7-linux-x86_64.egg/readline.so
>>> 

python -vv 的输出在这里

1个回答

9

lib/python2.7/site-packages/site.py文件通常不会被加载。这是因为它的职责是首先将site-packages路径添加到sys.path中,而位于site-packages中的site.py根本不可见。如果您在site-packages中有一个site.py,那么这是一个错误,那里不应该有这样的文件。

在未打补丁的Python中发生了什么:

  • Python启动,并带有有限的sys.path。除非您设置了包括它在内的PYTHONPATH变量,否则site-packages不是此列表的一部分。
  • Python导入site.py,它将导入在sys.path上列出的第一个site.py
  • 找到并加载lib/python2.7/site.py
  • site.pysite-packages添加到sys.path

就是这样,没有更多的 site.py 模块被加载。即使你尝试了,它也会找到已经导入的模块;sys.modules['site'] 存在并保存从 lib/python2.7/site.py 加载的对象。

然而,您的安装程序已安装了较旧的setuptools,其中包括一个特殊版本的site.py,如果不存在,easy_install命令将其安装到site-packages中。它将通过显式扫描原始sys.path并忽略任何由PYTHONPATH提供的路径,手动加载原始的site.py模块,使用低级函数imp.find_module()imp.load_module(),从而绕过正常的模块缓存。

它的目的是改变sys.path的顺序,以使列在PYTHONPATH中的.pth文件具有更高的优先级,请参见添加补丁的原始提交

注意:此版本包括一个被黑客攻击的'site.py',以支持处理在sys.path上位于site-packages之前的目录中的.pth文件。

该补丁已从更早的setuptools发布中完全删除,例如2006年的原始setuptools

所以,要么你的Linux发行版已经设置好将lib/python2.7/site-packages添加到你的PYTHONPATH中,要么你的shell已经为你设置好了,或者你的Python已经被打补丁包含了它,并且你的site-packages中有旧的setuptools“补丁”。
完全可以安全地删除该文件。

这个答案是明确且非常有帮助的。很可能,site-packages/site.py 是通过安装 setuptools 而来的。以前安装它到自定义 Python 安装路径的 旧方法 需要设置 PYTHONPATH。然而,easy_install 不再需要这样做。"[所有这些旧方法] 都被 Python 2.6 中 PEP-370 引入的用户方案所取代。" - cdunn2001

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接