Несоответствие между sys.executable и sys.version в Python
Установлены два интерпретатора Python:
[[email protected] ~]$ /usr/bin/python -V && /usr/local/bin/python -V
Python 2.4.3
Python 2.7.6
Судо изменяет PATH
для каждой команды, выполняемой следующим образом:
[[email protected] ~]$ 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
Я запускаю тест script:
[[email protected] ~]$ cat what_python.py
#!/usr/bin/env python
import sys
print sys.executable
print sys.version
[[email protected] ~]$ 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
?
Это продолжение моего вопроса Судо меняет PATH, но выполняет тот же двоичный файл
Ответы
Ответ 1
Оба @Graeme
Тот факт, что python не может получить это, говорит о том, что это делает свой собственный поиск PATH (...)
и @twalberg
(...) похоже, что sys.executable ищет текущий PATH вместо разрешая argv [0] (или, может быть, потому, что argv [0] - это простой питон в этом случай...), (...)
были в основном правы. Я не хотел верить, что 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 $PATH, since there no
* other way to find a directory to start the search from. If
* $PATH isn't exported, you lose.
*/
Как видно в моем случае, каждый проигрывает, когда первый Python при экспорте $PATH
отличается от выполняемого Python.
Более подробную информацию о процессе расчета размещения исполняемого файла интерпретатора можно найти в top файла getpath.c
:
Прежде чем выполнять какие-либо проверки, местоположение исполняемого файла определяется. Если argv [0] имеет одну или несколько косых черт, он используется без изменений. В противном случае он должен быть вызван из пути оболочки, поэтому мы ищем $PATH для именованного исполняемого файла и используем его. Если исполняемый файл не найден в $PATH (или не было среды $PATH переменная) используется исходная строка argv [0].
Далее, проверяемое место проверки проверяется, является ли оно символическим ссылка. Если это так, ссылка преследуется (правильно интерпретируя относительную путь, если он найден) и используется каталог целевого объекта ссылки.
Сделайте пару тестов, чтобы проверить это:
Если argv [0] имеет одну или несколько косых черт, он используется без изменений.
[[email protected] ~]$ 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)]
Ok.
Если исполняемый файл не был найден в $PATH (или не было переменной среды $PATH), используется исходная строка argv [0].
[[email protected] ~]$ 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-модуля documentation истинно. Если Python не может получить реальный путь к его исполняемому файлу, sys.executable будет пустая строка или None..
Посмотрим, добавляет ли добавление двоичного кода python в PATH
(после удаления sudo) проблема:
[[email protected] ~]$ 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 thread - к более строгому определению sys.executable
- Stackoverflow вопрос - как найти местоположение исполняемого файла в C
Ответ 2
Я думаю, что /usr/local/bin/python
- исполняемый файл. Строка версии почти наверняка скомпилирована в python
, поэтому она вряд ли ошибается. Посмотрите документацию для sys.executable
:
sys.executable
Строка, дающая абсолютный путь исполняемого двоичного файла для интерпретатора Python, в системах, где это имеет смысл. Если Python не может получить реальный путь к его исполняемому файлу, sys.executable будет пустой строкой или None.
Тот факт, что python
может быть не в состоянии получить это, предполагает, что он выполняет свой собственный поиск PATH
с помощью PATH
sudo set (который согласно моему ответу на предыдущий вопрос не совпадает с один из них использовался для поиска исполняемого файла).
Единственный способ быть уверенным здесь в том, чтобы прорвать реализацию python, но обычно я бы сказал, что строка версии, скорее всего, будет той, которой вы можете доверять. С другой стороны, sudo
использует execve
для выполнения команды (по крайней мере, согласно странице man
). Вы должны указать полный путь исполняемого файла к execve
(некоторые из вариантов exec
выполняют свой собственный поиск PATH
, этого нет). Поэтому для python
не нужно создавать sys.executable
.
Я не знаю, есть ли способ получить фактический argv[0]
для интерпретатора python
(sys.argv[0]
всегда является именем script или -c
), но это было бы интересно видеть. Если это /usr/local/bin/python
, это будет ошибкой в python
.
Я думаю, что лучше всего просто установить secure_path
в /etc/sudoers
, надеюсь, тогда вы получите некоторую согласованность.
Update
Фактически execve
принимает аргумент для исполняемого пути, а затем массив argv
, поэтому argv[0]
необязательно /usr/local/bin/python
. Вы все еще можете найти это, создав script как:
import time
time.sleep(60)
Затем запустите его и получите ps
, чтобы дать вам полный аргумент:
sudo python sleep.py &
ps -o args= -C python
Также, чтобы убедиться, что python
выполняется, вы можете сделать:
sudo ls -l /proc/PID/exe
во время работы программы.
Ответ 3
Каждый раз, когда вы запускаете интерпретатор 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 из командной строки.
- import sys
sys.version ## он должен быть последним.