example - python seaborn




Ist es machbar, Python mit Maschinencode zu kompilieren? (8)

Die Antwort ist "Ja, es ist möglich". Sie könnten Python-Code verwenden und versuchen, ihn mithilfe der CPython-API in den entsprechenden C-Code zu kompilieren. In der Tat gab es ein Python2C-Projekt, das genau das tat, aber ich habe seit vielen Jahren nichts mehr davon gehört (zurück in Python war es 1,5 Tage, als ich es das letzte Mal gesehen habe.)

Sie könnten versuchen, den Python-Code so weit wie möglich in natives C zu übersetzen und auf die CPython-API zurückzugreifen, wenn Sie tatsächliche Python-Funktionen benötigen. Ich habe die letzten ein oder zwei Monate mit dieser Idee gespielt. Es ist jedoch eine Menge Arbeit, und eine enorme Menge an Python - Features ist sehr schwer in C zu übersetzen: geschachtelte Funktionen, Generatoren, alles andere als einfache Klassen mit einfachen Methoden, alles was das Modifizieren von Modul - Globalen von außerhalb des Moduls betrifft , etc.

Wie durchführbar wäre es, Python (möglicherweise über eine intermediäre C-Repräsentation) in Maschinencode zu übersetzen?

Vermutlich müsste es eine Verbindung zu einer Python-Laufzeitbibliothek herstellen, und alle Teile der Python-Standardbibliothek, die Python selbst waren, müssten ebenfalls kompiliert (und verknüpft) werden.

Außerdem müssten Sie den Python-Interpreter bündeln, wenn Sie eine dynamische Auswertung von Ausdrücken durchführen möchten, aber vielleicht wäre eine Untergruppe von Python, die dies nicht erlaubt, trotzdem nützlich.

Würde es irgendwelche Vorteile bei der Geschwindigkeit und / oder Speichernutzung bieten? Vermutlich würde die Startzeit des Python-Interpreters entfallen (obwohl Shared Libraries beim Start noch geladen werden müssten).


Dies kompiliert Python nicht zu Maschinencode. Ermöglicht jedoch das Erstellen einer gemeinsam genutzten Bibliothek zum Aufrufen von Python-Code.

Wenn das, was Sie suchen, eine einfache Möglichkeit ist, Python-Code von C auszuführen, ohne sich auf Exec-Sachen zu verlassen. Sie könnten eine gemeinsam genutzte Bibliothek aus Python-Code generieren, die mit einigen Aufrufen der Python-Einbettungs-API umschlossen ist . Nun, die Anwendung ist eine gemeinsame Bibliothek, die Sie in vielen anderen Bibliotheken / Anwendungen verwenden können.

Hier ist ein einfaches Beispiel, das eine gemeinsame Bibliothek erstellt, die Sie mit einem C-Programm verknüpfen können. Die gemeinsam genutzte Bibliothek führt Python-Code aus.

Die Python-Datei, die ausgeführt wird, ist 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

Sie können es mit python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO') versuchen python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO') . Es wird ausgegeben:

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

Die gemeinsam genutzte Bibliothek wird von callpython.h folgt callpython.h :

#ifndef CALL_PYTHON
#define CALL_PYTHON

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

#endif

Die zugehörige callpython.c ist:

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

Sie können es mit dem folgenden Befehl kompilieren:

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

Erstellen Sie eine Datei mit dem Namen callpythonfromc.c , die Folgendes enthält:

#include "callpython.h"

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

Kompilieren Sie es und führen Sie Folgendes aus:

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

Dies ist ein sehr einfaches Beispiel. Es kann funktionieren, aber abhängig von der Bibliothek könnte es immer noch schwierig sein, C-Datenstrukturen zu Python und von Python zu C zu serialisieren. Dinge können etwas automatisiert werden ...

Nuitka könnte hilfreich sein.

Auch gibt es numba aber beide zielen nicht darauf ab, genau das zu tun, was du willst. Das Generieren eines C-Headers aus Python-Code ist möglich, aber nur, wenn Sie festlegen, wie die Python-Typen in C-Typen konvertiert werden oder diese Informationen ableiten können. Siehe python astroid für einen Python ast Analyzer.



Jython hat einen Compiler, der auf JVM-Bytecode abzielt. Der Bytecode ist voll dynamisch, genau wie die Python-Sprache selbst! Sehr cool. (Ja, wie die Antwort von Greg Hewgill andeutet, verwendet der Bytecode die Jython-Laufzeit und daher muss die Jython-JAR-Datei mit Ihrer App verteilt werden.)


Wie @Greg Hewgill es sagt, gibt es gute Gründe, warum dies nicht immer möglich ist. Bestimmte Arten von Code (wie sehr algorithmischer Code) können jedoch in "echten" Maschinencode umgewandelt werden.

Es gibt mehrere Möglichkeiten:

  • Verwenden Sie Psyco , das den Maschinencode dynamisch ausgibt. Sie sollten jedoch sorgfältig auswählen, welche Methoden / Funktionen konvertiert werden sollen.
  • Verwenden Sie Cython , eine Python- ähnliche Sprache, die in eine Python C-Erweiterung kompiliert wird
  • Verwenden Sie PyPy , das einen Übersetzer von RPython (eine eingeschränkte Teilmenge von Python, die einige der "dynamischsten" Funktionen von Python nicht unterstützt) zu C oder LLVM hat.
    • PyPy ist immer noch sehr experimentell
    • Nicht alle Erweiterungen sind vorhanden

Danach können Sie eines der vorhandenen Pakete (freeze, Py2exe, PyInstaller) verwenden, um alles in eine Binärdatei zu schreiben.

Alles in allem: Es gibt keine allgemeine Antwort auf Ihre Frage. Wenn Sie über Python-Code verfügen, der performancekritisch ist, versuchen Sie, so viel eingebaute Funktionalität wie möglich zu verwenden (oder fragen Sie nach einer Frage "Wie mache ich meinen Python-Code schneller?"). Wenn das nicht hilft, versuchen Sie, den Code zu identifizieren und an C (oder Cython) zu portieren, und verwenden Sie die Erweiterung.



Pyrex ist eine Teilmenge der Python-Sprache, die nach C kompiliert wird, von dem Typ, der zuerst Listenkompromittierungen für Python erstellt hat. Es wurde hauptsächlich für Gebäudehüllen entwickelt, kann aber in einem allgemeineren Kontext verwendet werden. Cython ist eine aktivere Variante von Pyrex.


Nuitka ist ein Python-zu-C ++ - Compiler, der mit libpython verlinkt. Es scheint ein relativ neues Projekt zu sein. Der Autor behauptet eine Geschwindigkeitsverbesserung gegenüber CPython auf dem pystone Benchmark.





compilation