Как я могу проверить версию Python в программе, которая использует новые возможности языка? - PullRequest
234 голосов
/ 15 января 2009

Если у меня есть сценарий Python, который требует по крайней мере определенного версия Python, как правильно грациозно провалиться когда для запуска скрипта используется более ранняя версия Python?

Как получить контроль достаточно рано, чтобы выдать сообщение об ошибке и выход?

Например, у меня есть программа, которая использует оператор ternery (новый в 2.5) и блоки with (новое в 2.6). Я написал простой маленький интерпретатор-версию рутина проверки, которая является первым, что скрипт позвони ... за исключением того, что это не так далеко. Вместо этого Сценарий завершается неудачно во время компиляции Python, прежде чем мои процедуры даже называются. Таким образом, пользователь сценария видит некоторые очень неясные трассировки ошибок Синакса - которые в значительной степени требуют эксперт, чтобы сделать вывод, что это просто случай бега неправильная версия Python.

Я знаю, как проверить версию Python. Проблема в том, что какой-то синтаксис недопустим в старых версиях Python. Рассмотрим эту программу:

import sys
if sys.version_info < (2, 4):
    raise "must use python 2.5 or greater"
else:
    # syntax error in 2.4, ok in 2.5
    x = 1 if True else 2
    print x

При запуске под 2.4, я хочу этот результат

$ ~/bin/python2.4 tern.py 
must use python 2.5 or greater

а не этот результат:

$ ~/bin/python2.4 tern.py 
  File "tern.py", line 5
    x = 1 if True else 2
           ^
SyntaxError: invalid syntax

(Ченнелинг для коллеги.)

Ответы [ 18 ]

2 голосов
/ 13 сентября 2011

Как отмечено выше, синтаксические ошибки возникают во время компиляции, а не во время выполнения. Хотя Python является «интерпретируемым языком», код Python фактически не интерпретируется напрямую; он компилируется в байтовый код, который затем интерпретируется. Существует этап компиляции, который происходит, когда модуль импортируется (если нет уже скомпилированной версии, доступной в виде файла .pyc или .pyd), и именно тогда вы получаете ошибку, а не (совершенно точно), когда ваш код работает

Вы можете отложить шаг компиляции и сделать это во время выполнения для одной строки кода, если хотите, используя eval, как отмечено выше, но я лично предпочитаю избегать этого, потому что это вызывает Python чтобы выполнить потенциально ненужную компиляцию во время выполнения, с одной стороны, и с другой стороны, это создает то, что для меня кажется беспорядком кода. (Если вы хотите, вы можете сгенерировать код, который генерирует код, который генерирует код - и у вас будет невероятное время, чтобы изменить и отладить его через 6 месяцев.) Поэтому вместо этого я бы порекомендовал нечто подобное:

import sys
if sys.hexversion < 0x02060000:
    from my_module_2_5 import thisFunc, thatFunc, theOtherFunc
else:
    from my_module import thisFunc, thatFunc, theOtherFunc

.. что я бы сделал, даже если бы у меня была только одна функция, использующая новый синтаксис, и она была очень короткой. (На самом деле, я бы принял все разумные меры, чтобы минимизировать количество и размер таких функций. Я мог бы даже написать такую ​​функцию, как ifTrueAElseB (cond, a, b) с этой единственной строкой синтаксиса.)

Еще одна вещь, на которую, возможно, стоит обратить внимание (на которую я немного удивлен, пока никто не указал), это то, что, хотя более ранние версии Python не поддерживали такой код, как

value = 'yes' if MyVarIsTrue else 'no'

.. он поддерживал код вроде

value = MyVarIsTrue and 'yes' or 'no'

Это был старый способ написания троичных выражений. У меня еще не установлен Python 3, но, насколько я знаю, этот «старый» способ работает до сих пор, так что вы можете сами решить, стоит ли его условно использовать новый синтаксис, если вам нужно поддерживать использование более старых версий Python.

1 голос
/ 16 июля 2018

Для автономных Python-скриптов работает следующий трюк с docstring модуля для обеспечения исполнения Python-версии (здесь v2.7.x) (протестировано на * nix).

#!/bin/sh
''''python -V 2>&1 | grep -q 2.7 && exec python -u -- "$0" ${1+"$@"}; echo "python 2.7.x missing"; exit 1 # '''

import sys
[...]

Это также должно обрабатывать отсутствующий исполняемый файл python, но зависит от grep. Смотрите здесь для фона.

1 голос
/ 09 мая 2012

Я только что нашел этот вопрос после быстрого поиска, пытаясь решить проблему самостоятельно, и я придумал гибрид, основанный на нескольких предложениях выше.

Мне нравится идея DevPlayer об использовании скрипта-обертки, но недостатком является то, что вы заканчиваете тем, что поддерживаете несколько оберток для разных ОС, поэтому я решил написать обертку на python, но использовать одну и ту же базовую версию, "захватить версию, запустив Отлично "логика и придумал это.

Я думаю, что это должно работать для 2.5 и далее. Я протестировал его на 2.66, 2.7.0 и 3.1.2 в Linux и 2.6.1 в OS X.

import sys, subprocess
args = [sys.executable,"--version"]

output, error = subprocess.Popen(args ,stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()
print("The version is: '%s'"  %error.decode(sys.stdout.encoding).strip("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLMNBVCXZ,.+ \n") )

Да, я знаю, что окончательная линия декодирования / полосы ужасна, но я просто хотела быстро получить номер версии. Я собираюсь уточнить это.

Пока это работает достаточно хорошо для меня, но если кто-нибудь сможет улучшить его (или скажите мне, почему это ужасная идея), это тоже будет круто.

1 голос
/ 15 января 2009

Я думаю, что лучший способ - это проверить функциональность, а не версии. В некоторых случаях это тривиально, а в других - нет.

например:

try :
    # Do stuff
except : # Features weren't found.
    # Do stuff for older versions.

Пока вы достаточно конкретны в использовании блоков try / Кроме того, вы можете охватить большинство ваших баз.

0 голосов
/ 12 декабря 2018

Я расширяю превосходный ответ Ахана, который печатает полезное сообщение до сценария Python даже скомпилированного.

Если вы хотите убедиться, что скрипт запускается с Python 3.6 или новее, добавьте эти две строки в начало вашего скрипта Python:

#!/bin/sh
''''python3 -c 'import sys; sys.exit(sys.version_info < (3, 6))' && exec python3 -u -- "$0" ${1+"$@"}; echo 'This script requires Python 3.6 or newer.'; exit 1 # '''

(Примечание. Вторая строка начинается с четырех одинарных кавычек и заканчивается тремя одинарными кавычками. Это может показаться странным, но это не опечатка.)

Преимущество этого решения в том, что код, подобный print(f'Hello, {name}!'), не вызовет SyntaxError, если используется версия Python старше 3.6. Вместо этого вы увидите это полезное сообщение:

This script requires Python 3.6 or newer.

Конечно, это решение работает только на Unix-подобных оболочках и только тогда, когда скрипт вызывается напрямую (например, ./script.py), и с установленными правильными битами разрешения eXecute.

0 голосов
/ 27 января 2018

Вы можете проверить с помощью sys.hexversion или sys.version_info.

sys.hexversion не очень удобен для человека, потому что это шестнадцатеричное число. sys.version_info - это кортеж, поэтому он более дружественный к человеку.

Проверьте для Python 3.6 или новее с sys.hexversion:

import sys, time
if sys.hexversion < 0x30600F0:
    print("You need Python 3.6 or greater.")
    for _ in range(1, 5): time.sleep(1)
    exit()

Проверьте для Python 3.6 или новее с sys.version_info:

import sys, time
if sys.version_info[0] < 3 and sys.version_info[1] < 6:
    print("You need Python 3.6 or greater.")
    for _ in range(1, 5): time.sleep(1)
    exit()

sys.version_info более дружественный к человеку, но требует больше персонажей. Я бы порекомендовал sys.hexversion, хотя он менее дружественен к человеку.

Надеюсь, это вам помогло!

0 голосов
/ 15 сентября 2009

Как насчет этого:

import sys

def testPyVer(reqver):
  if float(sys.version[:3]) >= reqver:
    return 1
  else:
    return 0

#blah blah blah, more code

if testPyVer(3.0) == 1:
  #do stuff
else:
  #print python requirement, exit statement
0 голосов
/ 09 апреля 2010

Проблема довольно проста. Вы проверили, была ли версия меньше 2,4, не меньше или равна . Так что, если версия Python 2.4, она не меньше 2.4. То, что вы должны были иметь:

    if sys.version_info **<=** (2, 4):

, а не

    if sys.version_info < (2, 4):
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...