Convertir tu código de Python 2 a Python 3

Python 2 llegó al final de su vida útil el 1 de enero de 2020. Python 3 está disponible desde 2008, pero la conversión de 2 a 3 ha sido lenta debido a las dependencias de bibliotecas que no estaban disponibles en Python 3 inicialmente, a que las versiones anteriores de python 3 eran más lentas que las de python 2 y también a que Python 2 funcionaba bastante bien para mucha gente. El fin de la vida útil de Python 2 significa que no habrá más versiones soportadas ni correcciones de errores por parte de Python. Algunas distribuciones de Linux, como Ubuntu y Red Hat, seguirán soportando Python 2 durante algún tiempo, pero migrar a Python 3 es una solución mejor.

¿Creía que Python 3 era compatible con Python 2?

No al 100%. El cambio de Python 2 a Python 3 se aprovechó para «arreglar» algunos problemas de Python 2. Entre ellos, la promoción de Unicode de forma más uniforme en todo el lenguaje y la aclaración de algunos problemas en la sintaxis, como el hecho de que print sea una sentencia en lugar de una función.

Algunas de las diferencias entre Python 2 y Python 3

Varias sentencias como print, exec y otras se han cambiado a funciones incorporadas. Ejemplos:

print 'hello world' # valid python 2 not in python 3
print ('hello world') # valid python 3 and later versions of python 2

También se ha cambiado la división de enteros. Ejemplo:

print (5 / 2) # in python 2 result is 2 in python 3 result is 2.5

// se ha añadido a python 3 para soportar el comportamiento antiguo

Muchas funciones ahora devuelven unicode/bytes en python 3 en lugar de cadenas ascii/str en python 2. Ejemplo:

type (subprocess.checkout_output('cmd')) # returns <class 'bytes'> <class 'bytes'=""> in python 3 vs <type 'str'><type 'str'=""> in python 2

Para convertir en python 3 <clase ‘bytes’><clase ‘bytes’=»»> en una cadena, deberás utilizar la opción .decode(‘ascii’).

type (subprocess.check_output('ls').decode('ascii')) # will result in a <class 'str'><class 'str'=""> in python 3

Algunas bibliotecas se han reorganizado.

Por ejemplo, la biblioteca urllib2 de python2 ha sido sustituida por la urllib de python 3. Urllib en Python 3 también está disponible en módulos como urllib.request y urllib.error, por lo que puedes importarlos para obtener una funcionalidad similar a la de python 2.

from urllib import urlopen # python 2
from urllib.request import urlopen # python 3

Convertir de Python 2 a Python 3 casi siempre de forma automática

Aunque puedes hacer todos los cambios para convertir tu script python de python 2 a python 3 a mano, hay una herramienta que hará gran parte del trabajo pesado por ti. 2to3 es un paquete que se puede instalar desde la biblioteca pip y también está disponible como paquete independiente en los repositorios de muchas distribuciones. Para instalar a través de pip3

% pip3 install 2to3

Para instalar en Debian/Ubuntu

% sudo apt install 2to3

Para instalar en Fedora/CentOS

% sudo yum install 2to3

Nota: al instalar desde pip obtendrás la última versión, mientras que las versiones de las distribuciones pueden ser un poco más antiguas, por lo que la instalación desde pip puede ser más adecuada para ti.

Ejecutar 2to3

$ 2to3 --help # will provide you the help message from the system

Un par de opciones interesantes

-l                  # will provide a list of the fixes available in 2to3.  E.g. print, exec, urllib, and others
-x                  # explicitly not run a transformation, use if one of the "fixes" doesn't work for your code base
-o                  # output dir, put transformed files into another location
--add-suffix=SUFFIX # put a suffix on converted files --add-suffix='3', will convert .py files to .py3 files
-w                  # overwrite current files with modified files

Suponiendo que tienes un directorio de código de python 2 (scripts) y una carpeta de destino para el código de python 3 (scripts3) puedes hacer lo siguiente: El comando para hacer la conversión es el siguiente

% 2to3 scripts -n -w -o scripts3

Las opciones son las siguientes

scripts  - source dir
-n       - no backups
-w       - write-unchanged files, write file even if no changes are required by 2to3
-o       - output directory
scripts3 - output directory, where the converted scripts are written

De este modo, el código original no se modifica y el usuario puede revisar el código convertido en la carpeta scripts3 y seguir consultando el código original.

Modernize es una envoltura de 2to3

Tiene un comportamiento similar al de 2to3, excepto que admite la bandera –six-unicode, que utilizará las seis funciones de ayuda que permiten soportar Python 3.1 y Python 3.2. Yo probablemente utilizaría 2to3 a menos que haya una característica convincente añadida a modernize que te anime a utilizarlo. Modernize también está disponible en algunas distribuciones como Debian testing y Arch. Para instalar

# pip3 install modernize

Ejecutar

# python-modernize --help

Consejos

Dos

Do conversion in small chunks
Do use tools like pylint to help you figure out problematic code, before you convert it
Do compare the code before and after the conversion
Do use the debugger to validate critical code

No hacer

Do not overwrite your code with 2to3, recommend a separate directory
Do not trust in the tools to do everything correctly

Prueba, prueba, prueba

Independientemente de cómo conviertas tu código de Python 2 a Python 3, debes probarlo a fondo. Para el código python de misión crítica, incluso sugeriría utilizar el depurador de python para ejecutar el código línea por línea.

# python3 -m pdb