问题:Python 中 sys.executable 和 sys.version 不匹配

安装了两个 Python 解释器:

[user@localhost ~]$ /usr/bin/python -V && /usr/local/bin/python -V
Python 2.4.3
Python 2.7.6

sudo 为它运行的每个命令更改PATH,如下所示:

[user@localhost ~]$ env | grep PATH && sudo env | grep PATH
PATH=/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/user/bin
PATH=/usr/bin:/bin

我运行一个测试脚本:

[user@localhost ~]$ cat what_python.py
#!/usr/bin/env python

import sys
print sys.executable
print sys.version
[user@localhost ~]$ sudo python what_python.py
/usr/bin/python
2.7.6 (default, Feb 27 2014, 17:05:07) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]

并获取sys.executable中 Python 2.4.3 和sys.version中报告的 2.7.6 版本的路径。显然sys.executablesys.version不匹配。考虑到 sudo 如何修改 PATH 我可以理解sys.executable的值。但是,为什么sys.version报告版本 2.7.6 而不是版本 2.4.3,这将匹配sys.executable报告的usr/bin/python路径?

这是我的问题Sudo 更改 PATH,但执行相同的二进制

解答

两个@Graeme

事实上,python 可能无法检索到这表明它正在执行自己的 PATH 搜索(...)

和@twalberg

(...) 它看起来像 sys.executable 搜索当前 PATH 而不是解析 argv[0] (或者可能因为 argv[0] 在这种情况下是简单的python...),(...)

基本上是对的。我不愿意相信 Python 会做一些如此简单(愚蠢?)的事情,比如使用PATH来定位自己,但这是真的。

Python 的sys模块在Python/sysmodule.c文件中实现。从 2.7.6 版本开始,sys.executable设置在1422行,如下所示:

 SET_SYS_FROM_STRING("executable",
                     PyString_FromString(Py_GetProgramFullPath()));

Py_GetProgramFullPath()函数在文件Modules/getpath.c中定义,从701行开始:

char *
Py_GetProgramFullPath(void)
{
    if (!module_search_path)
        calculate_path();
    return progpath;
}

函数calcuate_path()在同一个文件中定义,并包含以下注释:

/* If there is no slash in the argv0 path, then we have to
 * assume python is on the user's $PATH, since there's no
 * other way to find a directory to start the search from.  If
 * $PATH isn't exported, you lose.
 */

从我的例子中可以看出,当导出的$PATH上的第一个 Python 与正在运行的 Python 不同时,也会失败。

有关计算解释器可执行文件位置的过程的更多信息,可以在getpath.c文件的顶部中找到:

在完成任何搜索之前,确定可执行文件的位置。如果 argv[0] 中包含一个或多个斜杠,则它不会被使用。否则,它必须是从 shell 的路径调用的,所以我们在 $PATH 中搜索命名的可执行文件并使用它。如果在 $PATH 上找不到可执行文件(或没有 $PATH 环境变量),则使用原始 argv[0] 字符串。

接下来,检查可执行位置以查看它是否是符号链接。如果是这样,则跟踪链接(如果找到,则正确解释相对路径名)并使用链接目标的目录。

让我们做几个测试来验证上述内容:

如果 argv[0] 中有一个或多个斜杠,则使用原样

[user@localhost ~]$ sudo /usr/local/bin/python what_python.py
/usr/local/bin/python
2.7.6 (default, Feb 27 2014, 17:05:07) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]

好的。

如果在 $PATH 上找不到可执行文件(或没有 $PATH 环境变量),则使用原始 argv[0] 字符串。

[user@localhost ~]$ sudo PATH= python what_python.py
<empty line>
2.7.6 (default, Feb 27 2014, 17:05:07) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]

错误的。在这种情况下,来自 sys 模块的文档的语句为真 - 如果 Python 无法检索到其可执行文件的真实路径, sys.executable 将是一个空字符串或 None.

让我们看看是否将python二进制文件的位置添加回PATH(在sudo删除它之后)_fixes_问题:

[user@localhost ~]$ sudo PATH=$PATH python what_python.py
/usr/local/bin/python
2.7.6 (default, Feb 27 2014, 17:05:07) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-54)]

确实如此。

有关的:

  • Python 问题7774– sys.executable:如果修改了第零个命令参数,则位置错误。

  • Python 问题10835– sys.executable default 和 altinstall

  • python-dev 邮件列表线程– 对 sys.executable 进行更严格的定义

  • Stackoverflow问题– 如何在 C 中找到可执行文件的位置

Logo

Python社区为您提供最前沿的新闻资讯和知识内容

更多推荐