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

135 投票
2 回答
176584 浏览
提问于 2025-04-15 11:46

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 个回答

129

编辑

我在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的目录。

接下来,Python会检查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相同。如果在Windows上设置了applocal = true,则会跳过这一步。此时会使用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. 执行的脚本所在的目录会被添加到sys.path中。在Windows上,这始终是空字符串,这意味着Python会使用脚本所在的完整路径。
  2. 如果设置了PYTHONPATH环境变量,它的内容会被添加到sys.path中,除非你在Windows上,并且在pyvenv.cfg中设置了applocal为true。
  3. 压缩文件路径会被添加到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. 编译时宏PYTHONPATH中的路径会相对于动态找到的sys.prefix添加。
  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

57

“从环境变量 PYTHONPATH 初始化,并加上一个依赖于安装的默认值。”

-- http://docs.python.org/library/sys.html#sys.path

撰写回答