编辑
当我在2015年写这篇文章时,关于这个主题没有任何文档。根据评论,现在已经有文档了,如果您也想查看的话。在代码库的getpath.py
中的评论中也有算法的散文解释。我仍然认为我的答案是相关且相对最新的。
以下是原始文字
Python非常努力地智能设置sys.path
。它是如何设置的,可能会变得非常 复杂。以下指南是一个简化、不完整、有些错误但希望有用的指南,适用于普通的Python程序员,介绍了Python在正常的安装中如何确定sys.path
、sys.executable
、sys.exec_prefix
和sys.prefix
的初始值。
首先,Python会尽力根据操作系统提供的信息来确定自己实际上在文件系统中的位置。如果操作系统只是说“Python”正在运行,则它会在$PATH中找到自己。它解析任何符号链接。完成此操作后,找到的可执行文件的路径将用作
sys.executable
的值,没有任何条件。
接下来,它确定
sys.exec_prefix
和
sys.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.prefix
和
sys.exec_prefix
会被设置为该环境变量,
覆盖 pyvenv.cfg
中的任何
home = <DIRECTORY>
设置。在 Windows 上,如果存在
PYTHONHOME
环境变量,则
sys.prefix
和
sys.exec_prefix
也会被设置为该环境变量,
除非 pyvenv.cfg
中存在
home = <DIRECTORY>
设置,这时会使用该设置。
否则,这些
sys.prefix
和
sys.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.prefix
和
sys.exec_prefix
的值。Windows 等待
sys.path
完全被确定后才为
sys.prefix
设置一个回退值。
然后,(你一直在等待的,) Python 确定了要包含在
sys.path
中的初始值。
- Python执行脚本的目录被添加到
sys.path
中。在Windows上,这总是一个空字符串,告诉Python使用脚本所在的完整路径。
- 如果设置了PYTHONPATH环境变量,则将其内容添加到
sys.path
中,除非您在Windows上并且在pyvenv.cfg
中将applocal
设置为true。
- zip文件路径被添加到
sys.path
中,在Linux/Mac上是<prefix>/lib/python35.zip
,在Windows上是os.path.join(os.dirname(sys.executable), "python.zip")
。
- 如果在Windows上没有在
pyvenv.cfg
中设置applocal=true
,则添加注册表键HK_CURRENT_USER\Software\Python\PythonCore\<DLLVersion>\PythonPath\
的子键内容(如果有)。
- 如果在Windows上没有在
pyvenv.cfg
中设置applocal=true
,并且找不到sys.prefix
,则添加注册表键HK_CURRENT_USER\Software\Python\PythonCore\<DLLVersion>\PythonPath\
的核心内容(如果存在)。
- 如果在Windows上没有在
pyvenv.cfg
中设置applocal=true
,则添加注册表键HK_LOCAL_MACHINE\Software\Python\PythonCore\<DLLVersion>\PythonPath\
的子键内容(如果有)。
- 如果在Windows上没有在
pyvenv.cfg
中设置applocal=true
,并且找不到sys.prefix
,则添加注册表键HK_CURRENT_USER\Software\Python\PythonCore\<DLLVersion>\PythonPath\
的核心内容(如果存在)。
- 如果在Windows上未设置PYTHONPATH,未找到前缀,并且不存在任何注册表键,则将PYTHONPATH的编译时相对值添加;否则,忽略此步骤。
- 在动态查找到的
sys.prefix
相对路径中添加PYTHONPATH的编译时宏。
- 在Mac和Linux上,添加
sys.exec_prefix
的值。在Windows上,添加用于动态搜索sys.prefix
的目录。
在Windows上的这个阶段,如果没有找到前缀,则Python将尝试通过在
sys.path
中搜索所有目录来确定前缀,就像之前在
sys.executable
目录中所做的一样,直到找到为止。如果没有找到,
sys.prefix
将保持为空。
最后,在所有这些操作完成后,Python会加载
site
模块,该模块进一步向
sys.path
添加内容:
它首先从头部和尾部构造出最多四个目录。对于头部部分,它使用
sys.prefix
和
sys.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
。
sys.executable
应该是符号链接,但实际上如果argv[0]
包含斜杠,则它可能是符号链接,也可能是其他任何东西。实际的可执行文件路径(从execv(path, argv)
调用中)并未被使用。 - jfssys.path
的第一个问题:我总是将我的脚本目录的完整路径作为sys.path[0]
(而不是cwd ''
)。您应该能够执行类似于python some\other\path\than\cwd\main.py
的命令。 - ford04site-packages
中相关的文件有.pth
和.egg-link
后缀。 - florisla