¿Es posible compilar Python en código máquina?


¿Qué tan factible sería compilar Python (posiblemente a través de una representación C intermedia) en código máquina?

Presumiblemente tendría que vincularse a una biblioteca de tiempo de ejecución de Python, y cualquier parte de la biblioteca estándar de Python que fuera Python tendría que ser compilada (y enlazada) también.

Además, necesitaría empaquetar el intérprete de Python si quisiera hacer una evaluación dinámica de expresiones, pero quizás un subconjunto de Python que no lo permitiera aún lo haría ser útil.

¿Proporcionaría alguna ventaja de velocidad y/o uso de memoria? Presumiblemente se eliminaría el tiempo de inicio del intérprete de Python (aunque las bibliotecas compartidas aún necesitarían cargarse al inicio).

Author: Andy Balaam, 2008-09-26

12 answers

Pruebe ShedSkin el compilador Python-a-C++, pero está lejos de ser perfecto. También hay Psyco-Python JIT si solo se necesita speedup. Pero en mi humilde opinión esto no vale la pena. Para las partes críticas de la velocidad del código, la mejor solución sería escribirlas como extensiones de C / C++.

 22
Author: cleg,
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-07-03 13:45:14

Como dice @Greg Hewgill, hay buenas razones por las que esto no siempre es posible. Sin embargo, ciertos tipos de código (como el código muy algorítmico) se pueden convertir en código máquina "real".

Hay varias opciones:

  • Use Psyco, que emite código máquina dinámicamente. Sin embargo, debe elegir cuidadosamente qué métodos/funciones convertir.
  • Use Cython , que es un lenguaje Python - como que se compila en un Python C extensión
  • Use PyPy, que tiene un traductor de RPython (un subconjunto restringido de Python que no soporta algunas de las características más "dinámicas" de Python) a C o LLVM.
    • PyPy es todavía altamente experimental
    • no todas las extensiones estarán presentes

Después de eso, puede usar uno de los paquetes existentes (freeze, Py2exe, PyInstaller) para poner todo en un binario.

En general: no hay una respuesta general para tu pregunta. Si tiene código Python que es crítico para el rendimiento, intente usar la mayor cantidad de funcionalidad incorporada posible (o haga una pregunta de "Cómo hago que mi código Python sea más rápido"). Si eso no ayuda, intenta identificar el código y portarlo a C (o Cython) y usa la extensión.

 46
Author: Torsten Marek,
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-01-07 11:07:07

Py2c ( http://code.google.com/p/py2c ) puede convertir código python a c / c++ Soy el desarrollador en solitario de py2c.

 16
Author: Ramchandra Apte,
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-10 14:00:44

PyPy es un proyecto para reimplementar Python en Python, utilizando la compilación de código nativo como una de las estrategias de implementación (otras son una máquina virtual con JIT, usando JVM, etc.).). Sus versiones compiladas de C se ejecutan más lento que CPython en promedio, pero mucho más rápido para algunos programas.

Shedskin es un compilador experimental de Python a C++.

Pyrex es un lenguaje especialmente diseñado para escribir módulos de extensión de Python. Está diseñado para cerrar la brecha entre agradable, de alto nivel, fácil de usar mundo de Python y el desordenado, mundo de bajo nivel de C.

 13
Author: pdc,
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-03-05 08:07:49

Nuitka es un compilador de Python a C++ que enlaza con libpython. Parece ser un proyecto relativamente nuevo. El autor afirma una mejora de velocidad sobre CPython en el punto de referencia pystone.

 12
Author: bcattle,
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
2014-04-09 03:52:37

Pyrex es un subconjunto del lenguaje Python que compila a C, hecho por el tipo que primero construyó listas de comprensiones para Python. Fue desarrollado principalmente para envoltorios de construcción, pero se puede utilizar en un contexto más general. Cython es un tenedor más activamente mantenido de pyrex.

 10
Author: ConcernedOfTunbridgeWells,
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-10-14 09:24:16

Esto puede parecer razonable a primera vista, sin embargo, hay muchas cosas ordinarias en Python que no se pueden asignar directamente a una representación C sin tener que transferir gran parte del soporte de tiempo de ejecución de Python. Por ejemplo, escribir pato viene a la mente. Muchas funciones en Python que leen la entrada pueden tomar un objeto file o file-like, siempre y cuando soporte ciertas operaciones, por ejemplo. read() o readline(). Si piensas en lo que se necesitaría para mapear este tipo de soporte a C, comienzas para imaginar exactamente el tipo de cosas que el sistema de tiempo de ejecución de Python ya hace.

Hay utilidades como py2exe que agruparán un programa Python y el tiempo de ejecución en un solo ejecutable (en la medida de lo posible).

 9
Author: Greg Hewgill,
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
2008-09-26 09:56:08
 5
Author: serge-sans-paille,
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-10-27 10:37:32

Jython tiene un compilador dirigido a bytecode JVM. El bytecode es totalmente dinámico, al igual que el propio lenguaje Python! Muy guay. (Sí, como alude la respuesta de Greg Hewgill, el bytecode utiliza el tiempo de ejecución de Jython, por lo que el archivo jar de Jython debe distribuirse con su aplicación.)

 3
Author: Chris Jester-Young,
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
2008-09-26 10:00:16

Psyco es una especie de compilador just-in-time (JIT): compilador dinámico para Python, ejecuta código 2-100 veces más rápido, pero necesita mucha memoria.

En resumen: ejecuta su software Python existente mucho más rápido, sin cambios en su fuente, pero no compila a código objeto de la misma manera que lo haría un compilador de C.

 2
Author: Pierre-Jean Coudert,
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
2008-09-26 09:59:12

La respuesta es "Sí, es posible". Podría tomar código Python e intentar compilarlo en el código C equivalente utilizando la API CPython. De hecho, solía haber un proyecto Python2C que hacía precisamente eso, pero no he oído hablar de él en muchos años (en los días de Python 1.5 fue la última vez que lo vi.)

Podría intentar traducir el código Python a C nativo tanto como sea posible, y recurrir a la API CPython cuando necesite características reales de Python. He estado jugando con que idea de mí mismo el último mes o dos. Es, sin embargo, una gran cantidad de trabajo, y una enorme cantidad de características de Python son muy difíciles de traducir en C: funciones anidadas, generadores, cualquier cosa menos clases simples con métodos simples, cualquier cosa que implique modificar los globales de módulos desde fuera del módulo, etc, etc.

 2
Author: Thomas Wouters,
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
2008-09-26 10:14:09

Esto no compila Python a código máquina. Pero permite crear una biblioteca compartida para llamar código Python.

Si lo que está buscando es una manera fácil de ejecutar código Python desde C sin depender de cosas execp. Puede generar una biblioteca compartida a partir de código python envuelto con unas pocas llamadas a Python embedding API. Bueno, la aplicación es una biblioteca compartida, un. para que pueda utilizar en muchas otras bibliotecas / aplicaciones.

Aquí hay un ejemplo simple que crea un biblioteca compartida, que puede enlazar con un programa C. La biblioteca compartida ejecuta código Python.

El archivo python que se ejecutará es pythoncalledfromc.py:

# -*- encoding:utf-8 -*-
# this file must be named "pythoncalledfrom.py"

def main(string):  # args must a string
    print "python is called from c"
    print "string sent by «c» code is:"
    print string
    print "end of «c» code input"
    return 0xc0c4  # return something

Puedes probarlo con python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO'). Saldrá:

python is called from c
string sent by «c» code is:
HELLO
end of «c» code input

La biblioteca compartida se definirá de la siguiente manera por callpython.h:

#ifndef CALL_PYTHON
#define CALL_PYTHON

void callpython_init(void);
int callpython(char ** arguments);
void callpython_finalize(void);

#endif

El callpython.c asociado es:

// gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <python2.7/Python.h>

#include "callpython.h"

#define PYTHON_EXEC_STRING_LENGTH 52
#define PYTHON_EXEC_STRING "import pythoncalledfromc; pythoncalledfromc.main(\"%s\")"


void callpython_init(void) {
     Py_Initialize();
}

int callpython(char ** arguments) {
  int arguments_string_size = (int) strlen(*arguments);
  char * python_script_to_execute = malloc(arguments_string_size + PYTHON_EXEC_STRING_LENGTH);
  PyObject *__main__, *locals;
  PyObject * result = NULL;

  if (python_script_to_execute == NULL)
    return -1;

  __main__ = PyImport_AddModule("__main__");
  if (__main__ == NULL)
    return -1;

  locals = PyModule_GetDict(__main__);

  sprintf(python_script_to_execute, PYTHON_EXEC_STRING, *arguments);
  result = PyRun_String(python_script_to_execute, Py_file_input, locals, locals);
  if(result == NULL)
    return -1;
  return 0;
}

void callpython_finalize(void) {
  Py_Finalize();
}

Puede compilarlo con el siguiente comando:

gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so

Crear un archivo llamado callpythonfromc.c que contenga la siguiente:

#include "callpython.h"

int main(void) {
  char * example = "HELLO";
  callpython_init();
  callpython(&example);
  callpython_finalize();
  return 0;
}

Compilar y ejecutar:

gcc callpythonfromc.c callpython.so -o callpythonfromc
PYTHONPATH=`pwd` LD_LIBRARY_PATH=`pwd` ./callpythonfromc

Este es un ejemplo muy básico. Puede funcionar, pero dependiendo de la biblioteca puede ser difícil serializar las estructuras de datos de C a Python y de Python a C. Las cosas se pueden automatizar un poco...

Nuitka podría ser útil.

También hay numba pero ambos no apuntan a hacer lo que quieres exactamente. Generar un encabezado C a partir de código Python es posible, pero solo si se especifica el cómo convertir los tipos de Python a tipos C o puede inferir esa información. Ver python astroid para un analizador de Python ast.

 2
Author: amirouche,
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-23 11:46:55