Несоответствие между sys.executable и sys.version в Python

Установлены два интерпретатора Python:

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

Изменения в судо 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)]

и получить путь к Python 2.4.3 в sys.executable и версия 2.7.6 сообщается в sys.version, очевидно sys.executable а также sys.version не совпадают. Принимая во внимание, как sudo изменяет PATH, я могу понять значение sys.executable, Однако почему sys.version версия отчета 2.7.6, а не версия 2.4.3, которая будет соответствовать usr/bin/python путь сообщен sys.executable?

Это продолжение моего вопроса. Sudo изменяет PATH, но выполняет тот же двоичный файл.

3 ответа

Решение

Оба @Graeme

Тот факт, что python может быть не в состоянии извлечь это, говорит о том, что он выполняет свой собственный поиск PATH (…)

и @twalberg

(…) Похоже, что sys.executable ищет текущий PATH вместо разрешения argv[0] (или, возможно, потому что argv [0] в данном случае просто python)... (,)

были в основном правы. Я не хотел верить, что Python делает что-то настолько простое (глупое?), Как использование PATH найти себя, но это правда.

Питона 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.
 */

Как видно в моем случае, один проигрывает также, когда первый Python на экспорт $PATH отличается от запуска Python.

Более подробную информацию о процессе расчета размещения исполняемого файла переводчика можно найти в верхней части getpath.c файл:

Перед выполнением любых поисков определяется местоположение исполняемого файла. Если в argv [0] есть один или несколько слэшей, он используется без изменений. В противном случае он должен быть вызван из пути оболочки, поэтому мы ищем $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) исправляет проблему:

[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
  • Stackru вопрос - как найти расположение исполняемого файла в C

Я думаю /usr/local/bin/python исполняемый файл, который работает Строка версии почти наверняка скомпилирована в pythonтак что вряд ли это будет неправильно. Глядя на документацию для sys.executable:

sys.executable

Строка, задающая абсолютный путь к исполняемому двоичному файлу для интерпретатора Python в системах, где это имеет смысл. Если Python не может получить реальный путь к своему исполняемому файлу, sys.executable будет пустой строкой или None.

Дело в том, что python может быть не в состоянии получить это предполагает, что он делает свой собственный PATH поиск с использованием PATH sudo установил (что, согласно моему ответу на предыдущий вопрос, не совпадает с тем, которое он использовал для поиска исполняемого файла).

Единственный способ убедиться в этом - это изучить реализацию Python, но в целом я бы сказал, что строка версии, скорее всего, будет той, которой вы можете доверять. С другой стороны, хотя, sudo использования execve выполнить команду (хотя бы в соответствии с man страница). Вы должны указать полный путь к исполняемому файлу execve (некоторые из exec вариации делают свое PATH поиск, этот не). Поэтому это должно быть ежу понятно для python заполнить sys.executable,

Я не знаю, есть ли способ получить фактический argv[0] для python переводчик (sys.argv[0] всегда имя сценария или -c), но это было бы интересно посмотреть. Если это /usr/local/bin/pythonэто будет ошибка в python,

Я думаю, что лучшее, что нужно сделать, это просто установить secure_path в /etc/sudoersНадеюсь, тогда вы получите некоторую последовательность.

Обновить

На самом деле execve принимает аргумент для исполняемого пути, а затем argv массив, так argv[0] не обязательно /usr/local/bin/python, Вы все еще можете узнать это, сделав такой скрипт:

import time
time.sleep(60)

Затем запустите его и получите ps дать вам полную аргументацию:

sudo python sleep.py &
ps -o args= -C python

Также, чтобы быть уверенным, какой python выполняется, вы можете сделать:

sudo ls -l /proc/PID/exe

пока программа работает

Каждый раз, когда вы запускаете интерпретатор python, оболочка переходит в / usr / bin / python и выполняет его (попробуйте следующее: python -c "import os; print(os.environ['_'])").

Ну тогда как видите сами ln -l | grep python / usr / bin / python - это мягкая ссылка на исполняемый файл интерпретатора python.

То, что я сделал, было:

  1. Установите последнюю версию python (зайдите на сайт python, загрузите последний код и configure && make && make install)
  2. Проверьте местоположение этой последней версии исполняемого файла.
  3. Удалите софт-ссылку / usr / bin / python ##(вам потребуется разрешение root)
  4. ln -s <location последней исполняемой версии Python> /usr/bin/python ##(вполне вероятно, что нужен sudo)
  5. Запустите python из командной строки.
  6. импорт системы

sys.version ## это должно быть последним.

Другие вопросы по тегам