¿Cómo puedo comprobar la versión de Python en un programa que utiliza nuevas características de lenguaje?


Si tengo un script Python que requiere al menos un versión de Python, ¿cuál es la forma correcta de fallar con gracia cuando se utiliza una versión anterior de Python para iniciar el script?

¿Cómo obtengo el control lo suficientemente temprano como para emitir un mensaje de error ¿y salir?

Por ejemplo, tengo un programa que usa el operador ternery (nuevo en 2.5) y bloques "con" (nuevo en 2.6). Escribí una simple versión de intérprete rutina de comprobación que es lo primero que el script gustar llamada ... excepto que no llega tan lejos. En cambio, el script falla durante la compilación de python, antes de mis rutinas incluso se llaman. Por lo tanto, el usuario del script ve algunos muy rastreos de errores de synax oscuros - que más o menos requieren un experto para deducir que es simplemente el caso de ejecutar la versión equivocada de Python.

Sé cómo comprobar la versión de Python. El problema es que alguna sintaxis es ilegal en versiones anteriores de Python. Considere este programa:

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

Cuando se ejecuta bajo 2.4, quiero este resultado

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

Y no este resultado:

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

(Canalización para un compañero de trabajo.)

Author: Martin Thoma, 2009-01-15

17 answers

Puedes probar usando eval:

try:
  eval("1 if True else 2")
except SyntaxError:
  # doesn't have ternary

También, with es disponible en Python 2.5, simplemente agregue from __future__ import with_statement.

EDITAR: para obtener el control lo suficientemente temprano, puede dividirlo en diferentes archivos .py y verificar la compatibilidad en el archivo principal antes de importar (por ejemplo, en __init__.py en un paquete):

# __init__.py

# Check compatibility
try:
  eval("1 if True else 2")
except SyntaxError:
  raise ImportError("requires ternary support")

# import from another module
from impl import *
 104
Author: orip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-31 15:35:48

Tenga un envoltorio alrededor de su programa que haga lo siguiente.

import sys

req_version = (2,5)
cur_version = sys.version_info

if cur_version >= req_version:
   import myApp
   myApp.run()
else:
   print "Your Python interpreter is too old. Please consider upgrading."

También puede considerar el uso de sys.version(), si planea encontrar personas que están utilizando intérpretes de Python anteriores a la 2.0, pero luego tiene algunas expresiones regulares que hacer.

Y podría haber formas más elegantes de hacer esto.

 102
Author: Ed Carrel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-12 17:45:44

Intenta

import platform
platform.python_version()

Debería darte una cadena como "2.3.1". Si esto no es exactamente lo que desea, hay un rico conjunto de datos disponibles a través de la" plataforma " build-in. Lo que quieres debe estar ahí en alguna parte.

 28
Author: James Anderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-15 09:08:12

Probablemente la mejor manera de hacer esta comparación de versiones es usar el sys.hexversion. Esto es importante porque comparar tuplas de versión no le dará el resultado deseado en todas las versiones de python.

import sys
if sys.hexversion < 0x02060000:
    print "yep!"
else:
    print "oops!"
 21
Author: sorin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-28 12:38:59
import sys    
# prints whether python is version 3 or not
python_version = sys.version_info.major
if python_version == 3:
    print("is python 3")
else:
    print("not python 3")
 15
Author: Erick Wendel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-15 19:32:40

Respuesta de Nykakin en AskUbuntu:

También puede comprobar la versión de Python desde el propio código usando el módulo platform de la biblioteca estándar.

Hay dos funciones:

  • platform.python_version() (devuelve cadena).
  • platform.python_version_tuple() (devuelve la tupla).

El código Python

Crear un archivo por ejemplo: version.py)

Método fácil para comprobar la versión:

import platform

print(platform.python_version())
print(platform.python_version_tuple())

También puede utilizar el eval método:

try:
  eval("1 if True else 2")
except SyntaxError:
  raise ImportError("requires ternary support")

Ejecute el archivo Python en una línea de comandos:

$ python version.py 
2.7.11
('2', '7', '11')

La salida de Python con CGI a través de un servidor WAMP en Windows 10:

Captura de pantalla 2016-11-16 14.39.01 por Suriyaa Kudo


Recursos útiles

 9
Author: Suriyaa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-23 22:09:37

Los conjuntos se convirtieron en parte del lenguaje central en Python 2.4, con el fin de mantener la compatibilidad con versiones anteriores. Hice esto en ese entonces, que también funcionará para ti:

if sys.version_info < (2, 4):
    from sets import Set as set
 7
Author: André,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-12 17:46:38

Aunque la pregunta es: ¿Cómo obtengo el control lo suficientemente temprano como para emitir un mensaje de error y salir?

La pregunta que respondo es: ¿Cómo obtengo el control lo suficientemente temprano como para emitir un mensaje de error antes de iniciar la aplicación?

Puedo responder de manera muy diferente a las otras publicaciones. Parece que las respuestas hasta ahora están tratando de resolver tu pregunta desde dentro de Python.

Digo, hacer la comprobación de la versión antes de lanzar Python. Veo que tu camino es Linux o unix. Sin embargo, solo puedo ofrecerle un script de Windows. Me imagino que adaptarlo a la sintaxis de scripting de Linux no sería demasiado difícil.

Aquí está el script DOS con la versión 2.7:

@ECHO OFF
REM see http://ss64.com/nt/for_f.html
FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul
IF NOT ErrorLevel 1 GOTO Python27
ECHO must use python2.7 or greater
GOTO EOF
:Python27
python.exe tern.py
GOTO EOF
:EOF

Esto no ejecuta ninguna parte de su aplicación y, por lo tanto, no generará una excepción de Python. No crea ningún archivo temporal ni agrega ninguna variable de entorno del sistema operativo. Y no termina su aplicación a una excepción debido a las reglas de sintaxis de versiones diferentes. Eso es tres puntos de seguridad menos posibles de acceso.

La línea FOR /F es la clave.

FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul

Para múltiples versiones de python, compruebe la url: http://www.fpschultze.de/modules/smartfaq/faq.php?faqid=17

Y mi versión hack:

[MS script; Verificación de la versión de Python prelaunch del módulo Python] http://pastebin.com/aAuJ91FQ

 7
Author: DevPlayer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-02 03:39:26

Como se señaló anteriormente, los errores de sintaxis ocurren en tiempo de compilación, no en tiempo de ejecución. Si bien Python es un "lenguaje interpretado", el código Python no se interpreta directamente; se compila en código de bytes, que luego se interpreta. Hay un paso de compilación que ocurre cuando se importa un módulo (si no hay una versión ya compilada disponible en forma de a .pyc or .pyd) y ahí es cuando está recibiendo su error, no (exactamente) cuando su código se está ejecutando.

Puedes posponer el paso de compilar y hacer que suceda en tiempo de ejecución para una sola línea de código, si lo desea, mediante el uso de eval, como se señaló anteriormente, pero personalmente prefiero evitar hacer eso, porque hace que Python realice una compilación en tiempo de ejecución potencialmente innecesaria, por una cosa, y por otra, crea lo que para mí se siente como un desorden de código. (Si lo desea, puede generar código que genera código que genera código - y tener un tiempo absolutamente fabuloso modificando y depurando que en 6 meses a partir de ahora.) Así que lo que recomendaría en su lugar es algo más como esto:

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

.. lo cual haría incluso si solo tuviera una función que usara sintaxis más nueva y fuera muy corta. (De hecho, tomaría todas las medidas razonables para minimizar el número y el tamaño de tales funciones. Incluso podría escribir una función como ifTrueAElseB (cond, a, b) con esa sola línea de sintaxis en ella.)

Otra cosa que podría valer la pena señalar (que estoy un poco sorprendido de que nadie haya señalado todavía) es que mientras que las versiones anteriores de Python no soportaban código como

value = 'yes' if MyVarIsTrue else 'no'

Support soportaba código como

value = MyVarIsTrue and 'yes' or 'no'

Esa era la antigua forma de escribir expresiones ternarias. Todavía no tengo instalado Python 3, pero por lo que sé, esa forma "antigua" todavía funciona hasta el día de hoy, por lo que puede decidir por sí mismo si vale la pena usar condicionalmente la nueva sintaxis, si necesita admitir el uso de versiones anteriores de Python.

 2
Author: Shavais,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-13 02:27:02

Ponga lo siguiente en la parte superior de su archivo:

import sys

if float(sys.version.split()[0][:3]) < 2.7:
    print "Python 2.7 or higher required to run this code, " + sys.version.split()[0] + " detected, exiting."
    exit(1)

Luego continúe con el código Python normal:

import ...
import ...
other code...
 2
Author: jml,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-23 11:19:29
import sys
sys.version

Recibirá una respuesta como esta

'2.7.6 (por defecto, Oct 26 2016, 20:30:19) \n [CCG 4.8.4]"

Aquí 2.7.6 is version

 2
Author: Janarthanan Ramu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-24 05:26:49

Creo que la mejor manera es probar la funcionalidad en lugar de las versiones. En algunos casos, esto es trivial, no así en otros.

Eg:

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

Mientras seas lo suficientemente específico en usar los bloques try/except, puedes cubrir la mayoría de tus bases.

 1
Author: sykora,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-15 08:51:22

Acabo de encontrar esta pregunta después de una búsqueda rápida mientras intentaba resolver el problema por mí mismo y se me ocurrió un híbrido basado en algunas de las sugerencias anteriores.

Me gusta la idea de DevPlayer de usar un script wrapper, pero la desventaja es que terminas manteniendo múltiples wrappers para diferentes sistemas operativos, así que decidí escribir el wrapper en python, pero usar la misma lógica básica de "agarra la versión ejecutando el exe" y se me ocurrió esto.

Creo que debería funcionar para 2.5 y adelante. Lo he probado en 2.66, 2.7.0 y 3.1.2 en Linux y 2.6.1 en OS X hasta ahora.

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") )

Sí, sé que la línea final de decodificación/tira es horrible, pero solo quería agarrar rápidamente el número de versión. Voy a refinar.

Esto funciona lo suficientemente bien para mí por ahora, pero si alguien puede mejorarlo (o decirme por qué es una idea terrible) eso también sería genial.

 1
Author: Steve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-09 16:11:57

Puede consultar con sys.hexversion o sys.version_info.

sys.hexversion no es muy amigable con los humanos porque es un número hexadecimal. sys.version_info es una tupla, por lo que es más amigable con los humanos.

Compruebe si Python 3.6 o posterior con 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()

Compruebe si Python 3.6 o posterior con 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 es más amigable con los humanos, pero toma más personajes. Me gustaría recomendar sys.hexversion, a pesar de que es menos amigable con los humanos.

¡Espero que esto te haya ayudado!

 0
Author: Pb2007,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-27 19:26:55

Para los scripts python independientes, el siguiente truco de docstring del módulo para hacer cumplir una versión de python (aquí v2.7.x) funciona (probado en * 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
[...]

Esto también debería manejar el ejecutable de python que falta, pero tiene una dependencia de grep. Ver aquí para el fondo.

 0
Author: akhan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-15 23:17:25

¿qué tal esto:

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
 -2
Author: Pb2007,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-23 00:12:01

El problema es bastante simple. Se comprueba si la versión era menos de 2.4, no menos de o igual a. Así que si la versión de Python es 2.4, no es menor que 2.4. Lo que deberías haber tenido era:

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

, no

    if sys.version_info < (2, 4):
 -3
Author: Peter Mortensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-12 17:48:06