Domanda

Quanto sarebbe possibile compilare Python (possibilmente tramite una rappresentazione C intermedia) in codice macchina?

Presumibilmente avrebbe bisogno di collegarsi a una libreria di runtime Python e anche tutte le parti della libreria standard Python che erano Python stesse dovrebbero essere compilate (e collegate).

Inoltre, dovresti raggruppare l'interprete Python se volessi fare una valutazione dinamica delle espressioni, ma forse un sottoinsieme di Python che non lo consentiva sarebbe comunque utile.

Fornirebbe vantaggi in termini di velocità e / o memoria? Presumibilmente il tempo di avvio dell'interprete Python verrebbe eliminato (anche se le librerie condivise dovrebbero comunque essere caricate all'avvio).

È stato utile?

Soluzione

Prova ShedSkin compilatore Python-to-C ++, ma è tutt'altro che perfetto. Inoltre c'è Psyco - Python JIT se è necessaria solo la velocità. Ma IMHO non vale la pena. Per le parti critiche della velocità del codice, la soluzione migliore sarebbe scriverle come estensioni C / C ++.

Altri suggerimenti

Come dice @Greg Hewgill, ci sono buone ragioni per cui questo non è sempre possibile. Tuttavia, alcuni tipi di codice (come un codice molto algoritmico) possono essere trasformati in "reale" codice macchina.

Esistono diverse opzioni:

  • Utilizza Psyco , che emette dinamicamente il codice macchina. Tuttavia, dovresti scegliere attentamente quali metodi / funzioni convertire.
  • Usa Cython , che è un linguaggio Python- come che viene compilato in un Python Estensione C
  • Usa PyPy , che ha un traduttore di RPython (un sottoinsieme limitato di Python che lo fa non supporta alcune delle funzionalità più "dinamiche" di Python) in C o LLVM.
    • PyPy è ancora altamente sperimentale
    • non tutte le estensioni saranno presenti

Successivamente, puoi usare uno dei pacchetti esistenti (freeze, Py2exe, PyInstaller) per mettere tutto in un file binario.

Tutto sommato: non esiste una risposta generale alla tua domanda. Se disponi di un codice Python critico per le prestazioni, prova a utilizzare quante più funzionalità integrate possibili (oppure fai una domanda "Come posso rendere il mio codice Python più veloce"). Se ciò non aiuta, prova a identificare il codice e portarlo su C (o Cython) e utilizzare l'estensione.

py2c ( http://code.google.com/p/py2c ) può convertire il codice Python in c / C ++ Sono lo sviluppatore solista di py2c.

Nuitka è un compilatore da Python a C ++ che si collega a libpython. Sembra essere un progetto relativamente nuovo. L'autore afferma un miglioramento della velocità rispetto a CPython sul benchmark pystone.

PyPy è un progetto per reimplementare Python in Python, usando la compilazione in codice nativo come una delle strategie di implementazione ( altri essendo una VM con JIT, usando JVM, ecc.). Le loro versioni compilate in C funzionano in media più lentamente di CPython ma molto più velocemente per alcuni programmi.

Shedskin è un compilatore sperimentale da Python a C ++.

Pyrex è un linguaggio appositamente progettato per scrivere moduli di estensione Python. È progettato per colmare il divario tra il simpatico mondo di alto livello e facile da usare di Python e il disordinato mondo di basso livello di C.

Pyrex è un sottoinsieme del linguaggio Python che compila in C, fatto dal ragazzo che per primo ha creato comprensione delle liste per Python. È stato sviluppato principalmente per la costruzione di involucri ma può essere utilizzato in un contesto più generale. Cython è un fork di pyrex mantenuto più attivamente.

Questo potrebbe sembrare ragionevole a prima vista, tuttavia ci sono molte cose ordinarie in Python che non sono direttamente mappabili su una rappresentazione C senza trasportare molto del supporto di runtime di Python. Ad esempio, mi viene in mente la dattilografia. Molte funzioni in Python che leggono l'input possono richiedere un oggetto o simile a un file , purché supporti determinate operazioni, ad es. read () o readline (). Se pensi a cosa ci vorrebbe per mappare questo tipo di supporto a C, inizi a immaginare esattamente il genere di cose che il sistema di runtime Python già fa.

Esistono programmi di utilità come py2exe che raggrupperanno un programma Python e il runtime in un singolo eseguibile (fino ad ora il più possibile).

Alcuni riferimenti extra:

Jython ha un compilatore destinato al bytecode JVM. Il bytecode è completamente dinamico, proprio come il linguaggio Python stesso! Molto bello. (Sì, come allude alla risposta di Greg Hewgill, il bytecode utilizza il runtime Jython e quindi il file jar Jython deve essere distribuito con la tua app.)

Psyco è una specie di compilatore just-in-time (JIT): compilatore dinamico per Python, esegue il codice 2-100 volte più veloce, ma richiede molta memoria.

In breve: esegue il tuo software Python esistente molto più velocemente, senza alcun cambiamento nel tuo sorgente ma non si compila in codice oggetto allo stesso modo di un compilatore C.

La risposta è " Sì, è possibile " ;. Puoi prendere il codice Python e provare a compilarlo nel codice C equivalente usando l'API CPython. In effetti, c'era un progetto Python2C che faceva proprio questo, ma non ne ho sentito parlare da molti anni (in Python 1.5 giorni è l'ultima volta che l'ho visto.)

Potresti tentare di tradurre il codice Python in C nativa il più possibile e tornare all'API CPython quando hai bisogno delle effettive funzionalità di Python. Ho giocato con quell'idea anche io o l'ultimo mese o due. È, tuttavia, molto lavoro e un'enorme quantità di funzionalità di Python è molto difficile da tradurre in C: funzioni nidificate, generatori, tutt'altro che semplici classi con metodi semplici, tutto ciò che coinvolge la modifica dei globuli di moduli esterni al modulo, ecc. , ecc.

Questo non compila Python in codice macchina. Ma consente di creare una libreria condivisa per chiamare il codice Python.

Se quello che stai cercando è un modo semplice per eseguire il codice Python da C senza fare affidamento su cose execp. È possibile generare una libreria condivisa dal codice Python racchiuso in alcune chiamate a API di incorporamento Python . Bene, l'applicazione è una libreria condivisa, un .so che puoi usare in molte altre librerie / applicazioni.

Ecco un semplice esempio che crea una libreria condivisa, che puoi collegare a un programma C. La libreria condivisa esegue il codice Python.

Il file python che verrà eseguito è 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

Puoi provarlo con python2 -c " import pythoncalledfromc; pythoncalledfromc.main ( 'CIAO') . Produrrà:

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

La libreria condivisa verrà definita come segue da callpython.h :

#ifndef CALL_PYTHON
#define CALL_PYTHON

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

#endif

Il callpython.c associato è:

// 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();
}

Puoi compilarlo con il seguente comando:

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

Crea un file chiamato callpythonfromc.c che contiene quanto segue:

#include "callpython.h"

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

Compilalo ed eseguilo:

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

Questo è un esempio molto semplice. Può funzionare, ma a seconda della libreria potrebbe essere ancora difficile serializzare le strutture di dati C su Python e da Python a C. Le cose possono essere automatizzate in qualche modo ...

Nuitka potrebbe essere utile.

Inoltre c'è numba ma entrambi non mirano a fare esattamente quello che vuoi. La generazione di un'intestazione C dal codice Python è possibile, ma solo se si specifica il modo in cui convertire i tipi Python in tipi C o è possibile inferire tali informazioni. Vedi python astroid per un analizzatore Python ast.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top