È possibile compilare Python in codice macchina?


128

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, sarebbe necessario raggruppare l'interprete Python se si volesse 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).


2
A proposito, la tua domanda sarebbe IMHO più chiara se chiedessi "codice macchina" anziché codice oggetto.
Torsten Marek,

Risposte:


31

Prova il compilatore ShedSkin 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 ++.


5
Cordiali saluti, ShedSkin ha abbandonato il supporto di Windows.
sorin,

2
@sorin: beh, oggi supporta windows ... code.google.com/p/shedskin/downloads/…

2
La soluzione migliore, in modo rapido, potrebbe ancora essere PyPy .
Cees Timmerman,

shedskin non ha lavorato su di esso da circa due anni. :(
Perkins,

53

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 un codice macchina "reale".

Esistono diverse opzioni:

  • Usa Psyco , che emette dinamicamente il codice macchina. Tuttavia, dovresti scegliere attentamente quali metodi / funzioni convertire.
  • Usa Cython , che è un linguaggio simile a Python che viene compilato in un'estensione Python C.
  • Usa PyPy , che ha un traduttore da RPython (un sottoinsieme limitato di Python che 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 per la tua domanda. Se disponi di un codice Python critico per le prestazioni, prova a utilizzare quante più funzionalità integrate possibili (o 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.


3
Pypy è il successore di Psyco
bcattle

19

py2c ( https://github.com/pradyun/Py2C ) può convertire il codice python in c / c ++ Sono lo sviluppatore solista di py2c.


Questo sembra uno strumento utile. Viene ancora mantenuto?
Anderson Green,

@AndersonGreen È in una fase di sviluppo iniziale l'ultima volta che ci ho lavorato (probabilmente ora simile). Ho lasciato il progetto perché sono un po 'pigro. Se non hai notato il testo "Importante", ora è stato spostato su GitHub.
Ramchandra Apte,

Il collegamento punta a un installatore non verniciato , che sembra essere un progetto diverso. Py2c è ancora disponibile su GitHub?
Anderson Green,

@AndersonGreen Wow che è stato inosservato per così tanto tempo! Qui si va.
Ramchandra Apte,

Il link su code.google.com/p/py2c punta ancora al programma di installazione non modificato, quindi ora deve essere aggiornato.
Anderson Green,

15

PyPy è un progetto per reimplementare Python in Python, usando la compilazione in codice nativo come una delle strategie di implementazione (altre 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.


3
Cython è il fork di Pyrex più ampiamente utilizzato e sviluppato più attivamente.
Mike Graham,

"il simpatico mondo di alto livello e facile da usare di Python e il disordinato mondo di basso livello di C" - divertente stavo solo pensando a come C e assemblatore siano "belli" e semplici, e Python vive nel " disordinato mondo "di alto livello"
Ingegnere invertito il


10

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 accettare un file o un oggetto simile a un file , purché supporti determinate operazioni, ad es. read () o readline (). Se pensi a cosa sarebbe necessario 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 utility come py2exe che raggruppano un programma Python e il runtime in un singolo eseguibile (per quanto possibile).


1
E se il mio obiettivo fosse quello di assicurarmi che il codice venga compilato, poiché i linguaggi compilati staticamente (almeno secondo me) hanno meno probabilità di esplodere in fase di esecuzione? È possibile determinare che qualche foo.xespressione non funzionerà perché foonon avrà xnel momento in cui viene chiamata. Esistono controlli di codice statici per Python? Python può essere compilato in un assembly .Net ...
Hamish Grubijan,

10

Pyrex è un sottoinsieme del linguaggio Python che viene compilato in C, fatto dal ragazzo che per primo ha creato le comprensioni delle liste per Python. È stato sviluppato principalmente per la costruzione di involucri ma può essere utilizzato in un contesto più generale. Cython è una forchetta di pyrex mantenuta più attivamente.


2
Cython è la forcella di Pyrex più utilizzata e sviluppata attivamente.
Mike Graham,


3

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


2

Psyco è una specie di compilatore just-in-time (JIT): compilatore dinamico per Python, esegue il codice 2-100 volte più veloce, ma ha bisogno di 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 come farebbe un compilatore C.


2

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 nativo 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, qualsiasi cosa che coinvolga la modifica di globuli di moduli esterni al modulo, ecc. , eccetera.


2

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 all'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('HELLO'). Produrrà:

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

La libreria condivisa sarà 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 associato callpython.cè:

// 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

Creare un file denominato callpythonfromc.cche contiene quanto segue:

#include "callpython.h"

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

Compilalo ed esegui:

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.