Python 的 sys.path 是从哪里初始化的?

135

Python的sys.path是从哪里初始化的?

更新: 在引用PYTHONPATH之前,Python会添加一些路径:

    >>> import sys
    >>> from pprint import pprint as p
    >>> p(sys.path)
    ['',
     'C:\\Python25\\lib\\site-packages\\setuptools-0.6c9-py2.5.egg',
     'C:\\Python25\\lib\\site-packages\\orbited-0.7.8-py2.5.egg',
     'C:\\Python25\\lib\\site-packages\\morbid-0.8.6.1-py2.5.egg',
     'C:\\Python25\\lib\\site-packages\\demjson-1.4-py2.5.egg',
     'C:\\Python25\\lib\\site-packages\\stomper-0.2.2-py2.5.egg',
     'C:\\Python25\\lib\\site-packages\\uuid-1.30-py2.5.egg',
     'C:\\Python25\\lib\\site-packages\\stompservice-0.1.0-py2.5.egg',
     'C:\\Python25\\lib\\site-packages\\cherrypy-3.0.1-py2.5.egg',
     'C:\\Python25\\lib\\site-packages\\pyorbited-0.2.2-py2.5.egg',
     'C:\\Python25\\lib\\site-packages\\flup-1.0.1-py2.5.egg',
     'C:\\Python25\\lib\\site-packages\\wsgilog-0.1-py2.5.egg',
     'c:\\testdir',
     'C:\\Windows\\system32\\python25.zip',
     'C:\\Python25\\DLLs',
     'C:\\Python25\\lib',
     'C:\\Python25\\lib\\plat-win',
     'C:\\Python25\\lib\\lib-tk',
     'C:\\Python25',
     'C:\\Python25\\lib\\site-packages',
     'C:\\Python25\\lib\\site-packages\\PIL',
     'C:\\Python25\\lib\\site-packages\\win32',
     'C:\\Python25\\lib\\site-packages\\win32\\lib',
     'C:\\Python25\\lib\\site-packages\\Pythonwin']

我的 PYTHONPATH 是:

    PYTHONPATH=c:\testdir

我想知道在PYTHONPATH路径之前的那些路径是从哪里来的?

2个回答

127

编辑

当我在2015年写这篇文章时,关于这个主题没有任何文档。根据评论,现在已经有文档了,如果您也想查看的话。在代码库的getpath.py中的评论中也有算法的散文解释。我仍然认为我的答案是相关且相对最新的。

以下是原始文字

Python非常努力地智能设置sys.path。它是如何设置的,可能会变得非常 复杂。以下指南是一个简化、不完整、有些错误但希望有用的指南,适用于普通的Python程序员,介绍了Python在正常的安装中如何确定sys.pathsys.executablesys.exec_prefixsys.prefix初始值

首先,Python会尽力根据操作系统提供的信息来确定自己实际上在文件系统中的位置。如果操作系统只是说“Python”正在运行,则它会在$PATH中找到自己。它解析任何符号链接。完成此操作后,找到的可执行文件的路径将用作sys.executable的值,没有任何条件。
接下来,它确定sys.exec_prefixsys.prefix的初始值。
如果与sys.executable处于同一目录或向上一级目录存在名为pyvenv.cfg的文件,则Python会查看该文件。不同的操作系统对此文件有不同的处理方式。

这个配置文件中Python寻找的一个值是配置选项home = <DIRECTORY>。当Python动态设置sys.prefix的初始值时,它将使用这个目录而不是包含sys.executable的目录。如果在Windows上的pyvenv.cfg文件中出现了applocal = true设置,但没有home = <DIRECTORY>设置,则sys.prefix将被设置为包含sys.executable的目录。

接下来,会检查 PYTHONHOME 环境变量。在 Linux 和 Mac 上,如果存在 PYTHONHOME 环境变量,则 sys.prefixsys.exec_prefix 会被设置为该环境变量,覆盖 pyvenv.cfg 中的任何 home = <DIRECTORY> 设置。在 Windows 上,如果存在 PYTHONHOME 环境变量,则 sys.prefixsys.exec_prefix 也会被设置为该环境变量,除非 pyvenv.cfg 中存在 home = <DIRECTORY> 设置,这时会使用该设置。
否则,这些 sys.prefixsys.exec_prefix 会通过向后遍历 sys.executable 的位置或者 pyvenv.cfg 中给定的 home 目录来找到。
如果在该目录或其任何父目录中找到文件lib/python<version>/dyn-load,则在Linux或Mac上将该目录设置为sys.exec_prefix。如果在该目录或其任何子目录中找到文件lib/python<version>/os.py,则在Linux、Mac和Windows上将该目录设置为sys.prefix,并在Windows上将sys.exec_prefix设置为与sys.prefix相同的值。如果设置了applocal = true,则在Windows上跳过整个步骤。要么使用sys.executable的目录,要么如果在pyvenv.cfg中设置了home,则使用它作为sys.prefix的初始值。
如果找不到这些“标志性”文件或者 sys.prefix 还没有被找到,那么 Python 将把 sys.prefix 设置为一个“备用”值。例如,Linux 和 Mac 使用预编译的默认值作为 sys.prefixsys.exec_prefix 的值。Windows 等待 sys.path 完全被确定后才为 sys.prefix 设置一个回退值。
然后,(你一直在等待的,) Python 确定了要包含在 sys.path 中的初始值。
  1. Python执行脚本的目录被添加到sys.path中。在Windows上,这总是一个空字符串,告诉Python使用脚本所在的完整路径。
  2. 如果设置了PYTHONPATH环境变量,则将其内容添加到sys.path中,除非您在Windows上并且在pyvenv.cfg中将applocal设置为true。
  3. zip文件路径被添加到sys.path中,在Linux/Mac上是<prefix>/lib/python35.zip,在Windows上是os.path.join(os.dirname(sys.executable), "python.zip")
  4. 如果在Windows上没有在pyvenv.cfg中设置applocal=true,则添加注册表键HK_CURRENT_USER\Software\Python\PythonCore\<DLLVersion>\PythonPath\的子键内容(如果有)。
  5. 如果在Windows上没有在pyvenv.cfg中设置applocal=true,并且找不到sys.prefix,则添加注册表键HK_CURRENT_USER\Software\Python\PythonCore\<DLLVersion>\PythonPath\的核心内容(如果存在)。
  6. 如果在Windows上没有在pyvenv.cfg中设置applocal=true,则添加注册表键HK_LOCAL_MACHINE\Software\Python\PythonCore\<DLLVersion>\PythonPath\的子键内容(如果有)。
  7. 如果在Windows上没有在pyvenv.cfg中设置applocal=true,并且找不到sys.prefix,则添加注册表键HK_CURRENT_USER\Software\Python\PythonCore\<DLLVersion>\PythonPath\的核心内容(如果存在)。
  8. 如果在Windows上未设置PYTHONPATH,未找到前缀,并且不存在任何注册表键,则将PYTHONPATH的编译时相对值添加;否则,忽略此步骤。
  9. 在动态查找到的sys.prefix相对路径中添加PYTHONPATH的编译时宏。
  10. 在Mac和Linux上,添加sys.exec_prefix的值。在Windows上,添加用于动态搜索sys.prefix的目录。
在Windows上的这个阶段,如果没有找到前缀,则Python将尝试通过在sys.path中搜索所有目录来确定前缀,就像之前在sys.executable目录中所做的一样,直到找到为止。如果没有找到,sys.prefix将保持为空。
最后,在所有这些操作完成后,Python会加载site模块,该模块进一步向sys.path添加内容:
它首先从头部和尾部构造出最多四个目录。对于头部部分,它使用sys.prefixsys.exec_prefix;如果头部为空,则跳过。对于尾部部分,它使用空字符串,然后是lib/site-packages(在Windows上),或者是lib/pythonX.Y/site-packages,然后是lib/site-python(在Unix和Macintosh上)。对于每个不同的头部-尾部组合,它检查是否指向现有目录,如果是,则将其添加到sys.path,并检查新添加的路径中的配置文件。

编辑:自2021年12月以来,复杂单词开头的链接getpathp.c已被移除,因为实现已经转移到Python:getpath.py


2
尽管文档中写道sys.executable应该是符号链接,但实际上如果argv[0]包含斜杠,则它可能是符号链接,也可能是其他任何东西。实际的可执行文件路径(从execv(path, argv)调用中)并未被使用。 - jfs
1
关于您在Windows 10上关于sys.path的第一个问题:我总是将我的脚本目录的完整路径作为sys.path[0](而不是cwd '')。您应该能够执行类似于python some\other\path\than\cwd\main.py的命令。 - ford04
1
哇,这太棒了!在看到这个“真相”之前,我看了大约10个其他的问题和答案,尽管你谦虚地承认自己并不完全掌握所有知识。 - Mike Williamson
1
我想补充一下,在 site-packages 中相关的文件有 .pth.egg-link 后缀。 - florisla
简而言之,sys.path不会继承系统PATH环境变量的值。 - undefined
显示剩余8条评论

56

7
我猜它们来自于site模块:http://docs.python.org/library/site.html - ashcatch
21
网站模块会加载和解析位于您的site-packages目录中任何.pth文件的内容。这些.pth文件包含对您的PYTHONPATH的补充。 - ASk

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