Python es asombroso.
Sorprendentemente, esa es una declaración
bastante ambigua. ¿A qué me refiero con ‘Python’?, ¿Me refiero a la interfaz abstracta de
Python?, ¿Me refiero a CPython, la implementación común de Python (y no
confundir con Cython, que son similares en sus nombres)?, ¿O me refiero a algo
completamente distinto? Tal vez me esté
refiriendo indirectamente a Jython, o IronPython, o PyPy. O tal vez me he ido
al extremo y estoy hablando de RPython o RubyPython (los cuales son cosas muy,
muy distintas).
Mientras las tecnologías mencionadas anteriormente son
llamadas de formas parecidas y referenciadas de la misma manera, algunas de
ellas sirven para propósitos completamente distintos (o, al menos, operan de
maneras completamente distintas).
A lo largo de mi tiempo trabajando con Python, me topé con toneladas de estas herramientas .*ython.
Pero no hasta hace poco me tomé el tiempo de entender qué es lo que son, cómo
funcionan y por qué son necesarias (a sus maneras).
En este artículo, voy a empezar desde cero y recorreré
varias implementaciones de Python, concluyendo con una introducción detallada a
PyPy, el cual creo es el futuro del lenguaje.
Todo empieza con entender que es lo que ‘Python’ realmente
es.
Si tienes un buen entendimiento
sobre código binario, máquinas virtuales y parecidos, siéntete libre de saltarte esta parte.
“Python es interpretado o compilado?”
Este es un punto común de confusión para principiantes en
Python.
La primera cosa que hay que
saber es que ‘Python’ es una interfaz. Existe una especificación sobre
lo que Python debería hacer y cómo debería comportarse (cómo con cualquier
interfaz). Y hay múltiples implementaciones (como en cualquier interfaz).
Lo segundo que hay que
saber es que ‘interpretado’ y ‘compilado’ son propiedades de una implementación,
no de una interfaz.
Entonces, la pregunta no está realmente bien formada.
¿Python es interpretado o compilado? La
pregunta no está realmente bien formada.
Dicho esto, para la
implementación más común (CPython: escrito en C, usualmente llamado simplemente
‘Python’, y seguramente lo que estás usando si no tienes idea de lo que estoy
hablando), la respuesta es:interpretado,
con algunas partes compiladas.
CPython compila** el código fuente de Python a
*bytecode, y en ese momento interpreta ese bytecode, ejecutándolo sobre la
marcha.
* Nota:
no es una ‘compilación’ en sentido tradicional de la palabra. Normalmente, decimos
que ‘compilar’ es tomar el código de alto nivel y convertirlo en código
binario. Pero es un tipo de ‘compilación’.
Veamos la respuesta un poco más de cerca, ya que nos
permitirá entender algunos de los conceptos que surgirán más adelante en el
artículo.
Bytecode vs. código binario
Es muy importante entender la diferencia entre bytecode y
código binario (o nativo), tal vez mejor ilustrada con ejemplos:
·
C
compila a código binario, que luego es ejecutado directamente en tu procesador.
Cada instrucción le indica a tu CPU que mueva cosas alrededor.
·
Java
compila a bytecode, que luego es ejecutado en la máquina virtual de Java(Java
Virtual Machine, ó JVM), una abstracción de una computadora que ejecuta
programas. Cada instrucción es entonces manejada por la JVM, que interactúa con
tu computadora.
En términos breves: código
binario es más rápido, pero bytecode es más portable y seguro.
El código binario se ve distinto, dependiendo de tu
máquina, pero bytecode se ve igual en todas las maquinas. Se podría decir que
el código binario está optimizado para tu configuracion.
Volviendo a CPython, el proceso en el conjunto de
herramientas sucede de la siguiente manera:
1.
CPython
compila tu código Python a bytecode
2.
Ese
bytecode es entonces ejecutado en la Máquina Virtual CPython
Los principiantes asumen
que Python es compilado a raíz de los archivos .pyc. Hay alguna verdad en esto:
el archivo .pyc es bytecode compilado, que es después interpretado. Entonces si
haz ejecutado código Python y ya tienes un archivo .pyc disponible, el mismo va
a ejecutarse más rápido la segunda vez ya que no necesitará recompilar el
bytecode.
Maquinas virtuales alternativas: Jython, IronPython, y más
Cómo mencioné anteriormente, Python tiene varias
implementaciones. De vuelta, como mencioné antes, la más común es CPython. Ésta
es una implementación de Python escrita en C y es considerada la implementación
‘por defecto’.
¿Pero, qué pasa con las
alternativas? Una de las más prominentes es Jython, una implementación en Java que utiliza la JVM.
Mientras CPython produce bytecode para ser corrido en la VM de CPython, Jython
produce bytecode de Java para correr en la JVM (esto es lo
mismo que es producido cuando se compila un programa en Java).
“¿Por qué usaría alguna vez
una implementación alternativa?”, podrías preguntar. Bueno, para empezar, esasdiferentes implementaciones juegan muy bien con diferentes
conjuntos de tecnologías.
CPython hace muy fácil el
escribir extensiones C para tu código Python porque al final es ejecutado por
un intérprete de C. Por otro lado, Jython, facilita trabajar con otros
programas en Java: puedes importar cualquier clase de Java sin mayor esfuerzo,
evocando y utilizando tus clases Java dentro tus programas Jython. (Nota
aparte: si no pensaste en esto detalladamente, es una locura. Estamos en un
punto donde puedes mezclar y triturar diferentes lenguajes y compilarlos todos
en una misma esencia. Como fue mencionado por Rostin, los programas
que mezclan código Fortran y C están desde hace un tiempo. Así que, por
supuesto que esto no es algo necesariamente nuevo. Pero sigue siendo genial.)
Cómo ejemplo, esto es código Jython válido:
[Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_51 >>> from java.util import HashSet >>> s = HashSet(5) >>> s.add("Foo") >>> s.add("Bar") >>> s [Foo, Bar]
IronPython es otra implementación popular de
Python, escrita enteramente en C# y apuntando a la tecnología .NET. En
particular, corre con lo que se podría llamar la Máquina Virtual .NET,Common Language Runtime (CLR)de Microsoft, comparable
con la JVM.
Podrías decir que Jython : Java :: IronPython : C#. Corren
en sus respectivas VMs, puedes importar clases C# en tu código IronPython y
clases Java desde tu código Jython, etc.
Es totalmente posible sobrevivir sin tocar alguna vez una
implementación de Python no-CPython. Pero hay ventajas que se obtienen desde el
cambio, muchas de ellas son dependientes de la tecnología que uses. ¿Usas
muchos lenguajes basados en la JVM? Jython puede ser para tí. ¿Todo lo que haces
es sobre la tecnología .NET? Tal vez debas probar IronPython (y tal vez ya lo
hayas hecho).
Por cierto: mientras que
esto no sería una razón para usar una implementación diferente, nota que estas
implementaciones sí difieren en comportamiento más allá de como tratan tu
código fuente en Python. Sin embargo, esas diferencias son comúnmente menores,
y se disuelven o emergen con el tiempo mientras estas implementaciones se
encuentran bajo un activo desarrollo. Por ejemplo, IronPython usa cadenas Unicode por defecto;
Sin embargo, CPython, por defecto usa ASCII para
versiones 2.x (fallando con un error de codificaciónUnicodeEncodeError para
caracteres no-ASCII), pero sí soporta cadenas Unicode por defecto para lasversiones 3.x.
Compilación Justo-a-Tiempo: PyPy y el futuro
Por lo tanto, tenemos una implementación de Python escrita
en C, una en Java una en C#. El próximo paso lógico: una implementación de
Python escrita en… Python. (El lector educado encontrará esta notación
levemente engañosa).
Aquí es donde las cosas se ponen confusas. Primero,
discutamos sobre compilación Justo-a-Tiempo (Just-in-Time, ó JIT).
JIT:
El por qué y el cómo
Recordemos que el código
binario es mucho más rápido que bytecode. Bueno, ¿y si pudiéramos compilar algunas
partes de nuestro bytecode y luego correrlo como código nativo? Tendríamos que pagar algún precio al
compilar a bytecode (por ej., tiempo), pero si el resultado fuese más rápido,
eso sería genial! Esa es la motivación de la compilación JIT, una técnica
híbrida que mezcla los beneficios de los interpretadores y los compiladores. En
términos básicos, JIT quiere utilizar compilación para acelerar un sistema
interpretado.
Por ejemplo, un enfoque común tomado por la compilación
JIT:
1.
Identificar
bytecode que es ejecutado frecuentemente.
2.
Compilar
a código binario.
3.
Almacenar
el resultado en memoria caché.
4.
Siempre
que el mismo bytecode sea encontrado para ejecutar, en vez de usarlo, ejecutar
el código binario precompilado y cosechar los beneficios (por ej., aumentos de
velocidad)
De esto se trata PyPy:
llevar JIT a Python (mira el Apéndice para ver esfuerzos anteriores). Hay, por
supuesto, otros objetivos: PyPy apunta a ser multiplataforma, bajo en consumo
de memoria e independiente del conjunto de tecnologías. Pero JIT realmente se
vende por si solo. Como promedio de un puñado de pruebas de tiempo, se dice que
mejora el rendimiento a un factor de 6.27.
Para un mayor análisis, véase este cuadro del PyPySpeed Center:
Sign up here with your email
Déjame tus dudas y comentarios: Conversion Conversion Emoticon Emoticon