Question

Dans quelle mesure serait-il possible de compiler Python (éventuellement via une représentation en C intermédiaire) en code machine?

Il devrait probablement être lié à une bibliothèque d'exécution Python, et toutes les parties de la bibliothèque standard Python qui étaient Python elles-mêmes devraient également être compilées (et liées).

De même, vous devrez regrouper l'interpréteur Python si vous souhaitez effectuer une évaluation dynamique des expressions, mais un sous-ensemble de Python ne permettant pas cette opération serait néanmoins utile.

Fournirait-il des avantages en termes de vitesse et / ou d'utilisation de la mémoire? Vraisemblablement, le temps de démarrage de l'interpréteur Python serait éliminé (bien que les bibliothèques partagées auraient encore besoin d'être chargées au démarrage).

Était-ce utile?

La solution

Essayez de ShedSkin le compilateur Python-C ++, mais il est loin d'être parfait. En outre, il existe Psyco - Python JIT si seule une accélération est nécessaire. Mais à mon humble avis, cela ne vaut pas la peine. Pour les parties de code critiques pour la vitesse, la meilleure solution serait de les écrire en tant qu’extensions C / C ++.

Autres conseils

Comme le dit @Greg Hewgill, ce n’est pas toujours possible. Cependant, certains types de code (comme le code très algorithmique) peuvent être transformés en "réels". langage machine.

Il y a plusieurs options:

  • Utilisez Psyco , qui émet du code machine de manière dynamique. Vous devez cependant choisir avec soin les méthodes / fonctions à convertir.
  • Utilisez le Cython , qui est un langage Python- du type compilé dans un Python. Extension C
  • Utilisez PyPy , qui dispose d'un traducteur de RPython (un sous-ensemble restreint de Python qui ne prend pas en charge certaines des fonctionnalités les plus "dynamiques" de Python) en C ou LLVM.
    • PyPy est encore très expérimental
    • toutes les extensions ne seront pas présentes

Après cela, vous pouvez utiliser l'un des packages existants (freeze, Py2exe, PyInstaller) pour tout mettre dans un binaire.

Dans l’ensemble, il n’ya pas de réponse générale à votre question. Si le code Python est critique pour la performance, essayez d'utiliser autant de fonctionnalités intégrées que possible (ou posez la question "Comment rendre mon code Python plus rapide"). Si cela ne vous aide pas, essayez d'identifier le code, de le transférer en C (ou Cython) et d'utiliser l'extension.

py2c ( http://code.google.com/p/py2c ) peut convertir le code python en c / c ++ Je suis le développeur solo de py2c.

Nuitka est un compilateur Python vers C ++ qui établit un lien avec libpython. Cela semble être un projet relativement nouveau. L’auteur revendique une amélioration de la vitesse par rapport à CPython dans le référentiel pystone.

PyPy est un projet visant à réimplémenter Python dans Python, en utilisant la compilation en code natif comme l'une des stratégies d'implémentation ( les autres étant une machine virtuelle avec JIT, utilisant JVM, etc.). Les versions C compilées fonctionnent en moyenne plus lentement que CPython mais beaucoup plus rapidement pour certains programmes.

Shedskin est un compilateur expérimental Python-to-C ++.

Pyrex est un langage spécialement conçu pour écrire des modules d'extension Python. Il est conçu pour combler le fossé entre le monde agréable, de haut niveau et facile à utiliser de Python et le monde désordonné de C.

.

Pyrex est un sous-ensemble du langage Python qui compile to C, réalisé par le gars qui a créé la liste des compréhensions pour Python. Il a été principalement développé pour les enveloppes de construction, mais peut être utilisé dans un contexte plus général. Cython est un fork de pyrex maintenu plus activement.

Cela peut sembler raisonnable au premier abord, mais il y a beaucoup de choses ordinaires dans Python qui ne sont pas directement mappables à une représentation en C sans transférer une grande partie du support d'exécution Python. On pense par exemple à la frappe de canard. De nombreuses fonctions en Python qui lisent les entrées peuvent prendre un objet fichier ou semblable à un fichier , à condition qu'il prenne en charge certaines opérations, par exemple. read () ou readline (). Si vous réfléchissez à ce qu’il faudrait pour mapper ce type de support sur C, vous commencez à imaginer exactement le genre de choses que fait déjà le système d’exécution Python.

Il existe des utilitaires tels que py2exe qui regroupent un programme Python et un environnement d'exécution dans un seul exécutable (dans la mesure du possible). possible).

Quelques références supplémentaires:

Jython dispose d’un compilateur ciblant le bytecode de la machine virtuelle Java. Le bytecode est totalement dynamique, tout comme le langage Python lui-même! Très sympa. (Oui, comme le dit la réponse de Greg Hewgill, le bytecode utilise le runtime de Jython et le fichier jar de Jython doit être distribué avec votre application.)

Psyco est une sorte de compilateur juste à temps (JIT): compilateur dynamique pour Python, exécute le code de 2 à 100 fois plus rapidement, mais nécessite beaucoup de mémoire.

En bref: il exécute votre logiciel Python existant beaucoup plus rapidement, sans modification de votre source, mais il ne compile pas en code objet de la même manière qu'un compilateur C.

La réponse est "Oui, c'est possible". Vous pouvez prendre du code Python et essayer de le compiler dans le code C équivalent à l'aide de l'API CPython. En fait, il y avait un projet Python2C qui faisait exactement cela, mais je n'en avais pas entendu parler depuis de nombreuses années (il était de retour dans Python 1.5 jours lorsque je l'ai vu pour la dernière fois.)

Vous pouvez essayer de traduire le code Python en C natif autant que possible et de revenir à l'API CPython lorsque vous avez besoin de fonctionnalités Python réelles. Je me suis moqué de cette idée moi-même depuis un ou deux mois. Cependant, cela représente un travail énorme, et une quantité énorme de fonctionnalités Python est très difficile à traduire en C: fonctions imbriquées, générateurs, tout sauf des classes simples avec des méthodes simples, tout ce qui implique la modification de globaux de modules depuis l'extérieur du module, etc. , etc.

Ceci ne compile pas Python en code machine. Mais permet de créer une bibliothèque partagée pour appeler du code Python.

Si ce que vous recherchez est un moyen facile d’exécuter du code Python à partir de C sans faire appel à execp. Vous pouvez générer une bibliothèque partagée à partir de code python encapsulé avec quelques appels à API d’intégration Python . L’application est une bibliothèque partagée, un fichier .so que vous pouvez utiliser dans de nombreuses autres bibliothèques / applications.

Voici un exemple simple de création d’une bibliothèque partagée, que vous pouvez relier à un programme C. La bibliothèque partagée exécute le code Python.

Le fichier python qui sera exécuté est 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

Vous pouvez l’essayer avec python2 -c " importer pythoncalledfromc; pythoncalledfromc.main ('HELLO') . Il va générer:

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

La bibliothèque partagée sera définie comme suit par callpython.h :

#ifndef CALL_PYTHON
#define CALL_PYTHON

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

#endif

Le callpython.c associé est:

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

Vous pouvez le compiler avec la commande suivante:

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

Créez un fichier nommé callpythonfromc.c contenant les éléments suivants:

#include "callpython.h"

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

Compilez-le et exécutez:

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

Ceci est un exemple très basique. Cela peut fonctionner, mais selon la bibliothèque, il peut être encore difficile de sérialiser des structures de données C en Python et de Python en C. Les choses peuvent être quelque peu automatisées ...

Nuitka pourrait être utile.

De plus, il existe numba , mais ils ne visent pas tous les deux à faire exactement ce que vous voulez. La génération d'un en-tête C à partir de code Python est possible, mais uniquement si vous indiquez comment convertir les types Python en types C ou si vous pouvez en déduire ces informations. Voir python astroid pour un analyseur ast en python.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top