Несоответствие между 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.
То, что я сделал, было:
- Установите последнюю версию python (зайдите на сайт python, загрузите последний код и
configure && make && make install
) - Проверьте местоположение этой последней версии исполняемого файла.
- Удалите софт-ссылку / usr / bin / python ##(вам потребуется разрешение root)
ln -s <location
последней исполняемой версии Python> /usr/bin/python ##(вполне вероятно, что нужен sudo)- Запустите python из командной строки.
- импорт системы
sys.version ## это должно быть последним.