Appeler C / C++ de Python?
quelle serait la façon la plus rapide de construire une liaison Python vers une bibliothèque c/" class="blnk">C ou C++?
(J'utilise Windows si cela compte.)
14 réponses
vous devriez jeter un oeil à Boost.Python . Voici la courte introduction tirée de leur site web:
la bibliothèque Boost Python est un framework pour interfacer Python et C.++ Il vous permet d'exposer rapidement et de manière transparente les classes c++ fonctions et objets en Python, et vice-versa, n'utilisant aucun outils -- compilateur C++. Il est conçu pour envelopper les interfaces C++ non-intrusive, de sorte que vous ne devriez pas il faut changer le code C++ à tout ça pour l'emballer et le Booster.Python idéal pour exposer Bibliothèques de tiers à Python. La bibliothèque de pointe les techniques de métaprogrammation simplifie sa syntaxe pour les utilisateurs, de sorte que emballage code prend l'aspect d'une sorte d'interface déclarative definition language (IDL).
ctypes fait partie de la bibliothèque standard, et est donc plus stable et largement disponible que swig , qui a toujours eu tendance à me donner problèmes .
avec ctypes, vous devez satisfaire toute dépendance du temps de compilation sur python, et votre liaison fonctionnera sur n'importe quel python qui a des ctypes, pas seulement celui contre lequel il a été compilé.
supposons que vous ayez un simple C++ exemple de classe à qui vous voulez parler dans un fichier foo.cpp:
#include <iostream>
class Foo{
public:
void bar(){
std::cout << "Hello" << std::endl;
}
};
puisque les ctypes ne peuvent parler qu'aux fonctions C, vous devez fournir ceux qui les déclarent comme externes" c "
extern "C" {
Foo* Foo_new(){ return new Foo(); }
void Foo_bar(Foo* foo){ foo->bar(); }
}
Ensuite, vous devez compiler une bibliothèque partagée
g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o
et finalement vous devez écrire votre wrapper python (par ex. fooWrapper.py)
from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')
class Foo(object):
def __init__(self):
self.obj = lib.Foo_new()
def bar(self):
lib.Foo_bar(self.obj)
une fois que vous avez que vous pouvez appeler comme
f = Foo()
f.bar() #and you will see "Hello" on the screen
le moyen le plus rapide pour faire ceci est d'utiliser SWIG .
exemple de SWIG tutorial :
/* File : example.c */
int fact(int n) {
if (n <= 1) return 1;
else return n*fact(n-1);
}
fichier D'Interface:
/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern int fact(int n);
%}
extern int fact(int n);
construire un module Python sur Unix:
swig -python example.i
gcc -fPIC -c example.c example_wrap.c -I/usr/local/include/python2.7
gcc -shared example.o example_wrap.o -o _example.so
Utilisation:
>>> import example
>>> example.fact(5)
120
Notez que vous devez avoir python-dev. Aussi, dans certains systèmes, les fichiers d'en-tête python seront /usr/include/python2.7 basé sur la façon dont vous l'avez installé.
du tutoriel:
SWIG est un compilateur C++ assez complet avec support pour presque toutes les fonctionnalités linguistiques. Cela inclut le prétraitement, les pointeurs, les classes, l'héritage, et même les modèles C++. SWIG peut également être utilisé pour empaqueter des structures et des classes dans des classes mandataires dans la langue cible - exposant la fonctionnalité sous-jacente d'une manière très naturelle.
j'ai commencé mon voyage dans le python < - > C++ binding à partir de cette page, avec l'objectif de relier des types de données de haut niveau (vecteurs STL multidimensionnels avec des listes Python): -)
ayant essayé les solutions basées à la fois sur ctypes et boost.python (et n'étant pas un ingénieur logiciel) je les ai trouvés complexes lorsque la liaison de haut niveau des types de données est nécessaire, alors que j'ai trouvé SWIG beaucoup plus simple pour de tels cas.
cet exemple utilise donc SWIG, et il a été testé sous Linux (mais SWIG est disponible et largement utilisé sous Windows).
l'objectif est de rendre une fonction C++ disponible à Python qui prend une matrice sous forme de vecteur 2D STL et retourne une moyenne de chaque ligne (comme vecteur 1D STL).
le code en C++ ("code.rpc") est comme suit:
#include <vector>
#include "code.h"
using namespace std;
vector<double> average (vector< vector<double> > i_matrix) {
// Compute average of each row..
vector <double> averages;
for (int r = 0; r < i_matrix.size(); r++){
double rsum = 0.0;
double ncols= i_matrix[r].size();
for (int c = 0; c< i_matrix[r].size(); c++){
rsum += i_matrix[r][c];
}
averages.push_back(rsum/ncols);
}
return averages;
}
le en-tête équivalent ("code.h") est:
#ifndef _code
#define _code
#include <vector>
std::vector<double> average (std::vector< std::vector<double> > i_matrix);
#endif
nous compilons d'abord le code C++ pour créer un fichier objet:
g++ -c -fPIC code.cpp
nous définissons alors un fichier de définition d'interface de SWIG ("code.i") pour nos fonctions C++.
%module code
%{
#include "code.h"
%}
%include "std_vector.i"
namespace std {
/* On a side note, the names VecDouble and VecVecdouble can be changed, but the order of first the inner vector matters! */
%template(VecDouble) vector<double>;
%template(VecVecdouble) vector< vector<double> >;
}
%include "code.h"
en utilisant SWIG, nous générons un code source de l'interface C++ à partir du fichier de définition de L'interface SWIG..
swig -c++ -python code.i
nous compilons enfin le C++généré interfacez le fichier source et liez tout ensemble pour générer une bibliothèque partagée directement importable par Python (les " _ "matters):
g++ -c -fPIC code_wrap.cxx -I/usr/include/python2.7 -I/usr/lib/python2.7
g++ -shared -Wl,-soname,_code.so -o _code.so code.o code_wrap.o
nous pouvons maintenant utiliser la fonction dans les scripts Python:
#!/usr/bin/env python
import code
a= [[3,5,7],[8,10,12]]
print a
b = code.average(a)
print "Assignment done"
print a
print b
Check out pyrex or Cython . Ce sont des langages de type Python pour l'interfaçage entre C/C++ et Python.
il y a aussi pybind11
, qui est comme une version légère de Boost.Python et compatible avec tous les compilateurs C++ modernes:
ce papier, affirmant que Python est tout ce dont un scientifique a besoin , dit essentiellement: premier prototype tout en Python. Ensuite, lorsque vous avez besoin d'accélérer une pièce, utilisez SWIG et traduisez cette partie en C.
Je ne l'ai jamais utilisé mais j'ai entendu de bonnes choses sur ctypes . Si vous essayez de l'utiliser avec C++, assurez-vous d'éviter le nom mangling via extern "C"
. Merci pour le commentaire, Florian Bösch.
je pense que cffi pour python peut être une option.
le but est d'appeler le code C de Python. Vous devriez être en mesure de le faire sans apprendre une troisième langue: chaque alternative exige que vous apprenez leur propre langue (Cython, SWIG) ou API (ctypes). Nous avons donc essayé pour supposer que vous connaissez Python et C et minimiser les bits supplémentaires de API que vous devez apprendre.
L'un des documents officiels de Python contient des détails sur extending Python using C/C++ . Même sans l'utilisation de SWIG , il est assez simple et fonctionne parfaitement bien sur Windows.
pour C++ moderne, utilisez cppyy: http://cppyy.readthedocs.io/en/latest /
est basé sur Cling, l'interpréteur C++ Pour Clang/LLVM. Les reliures sont à l'exécution et aucun langage intermédiaire supplémentaire n'est nécessaire. Grâce à Clang, il supporte C++17.
installez-le en utilisant pip:
$ pip install cppyy
pour les petits projets, il suffit de charger la bibliothèque pertinente et les en-têtes qui vous intéressent. Par exemple: prenez le code de l'exemple ctypes est ce thread, mais divisé en en-tête et les sections de code:
$ cat foo.h
class Foo {
public:
void bar();
};
$ cat foo.cpp
#include "foo.h"
#include <iostream>
void Foo::bar() { std::cout << "Hello" << std::endl; }
compiler it:
$ g++ -c -fPIC foo.cpp -o foo.o
$ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o
et l'utiliser:
$ python
>>> import cppyy
>>> cppyy.include("foo.h")
>>> cppyy.load_library("foo")
>>> from cppyy.gbl import Foo
>>> f = Foo()
>>> f.bar()
Hello
>>>
les grands projets sont pris en charge avec le chargement automatique des informations de réflexion préparées et des fragments cmake pour les créer, de sorte que les utilisateurs des paquets installés puissent simplement exécuter:
$ python
>>> import cppyy
>>> f = cppyy.gbl.Foo()
>>> f.bar()
Hello
>>>
grâce à LLVM, fonctionnalités avancées sont possibles, comme l'instanciation automatique de template. Pour reprendre l'exemple:
>>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]()
>>> v.push_back(f)
>>> len(v)
1
>>> v[0].bar()
Hello
>>>
Note: je suis l'auteur de cppyy.
la question Est de savoir comment appeler une fonction C de Python, Si j'ai bien compris. Ensuite, le meilleur pari sont Ctypes (BTW portable à travers toutes les variantes de Python).
>>> from ctypes import *
>>> libc = cdll.msvcrt
>>> print libc.time(None)
1438069008
>>> printf = libc.printf
>>> printf("Hello, %s\n", "World!")
Hello, World!
14
>>> printf("%d bottles of beer\n", 42)
42 bottles of beer
19
pour un guide détaillé, vous pouvez vous référer à mon article de blog .
Cython est définitivement la voie à suivre, sauf si vous prévoyez d'écrire Java wrappers, auquel cas SWIG peut être préférable.
je recommande l'utilisation de l'utilitaire en ligne de commande runcython
, il rend le processus D'utilisation de Cython extrêmement facile. Si vous avez besoin de passer des données structurées à C++, jetez un oeil à la bibliothèque protobuf de Google, c'est très pratique.
voici un minimum d'exemples que j'ai fait qui utilise les deux outils:
https://github.com/nicodjimenez/python2cpp
espère qu'il peut être un point de départ utile.
vous devez d'abord décider quel est votre but particulier. La documentation officielle de Python sur étendre et intégrer l'interpréteur Python a été mentionnée ci-dessus, je peux ajouter un bon aperçu des extensions binaires . Les cas d'utilisation peuvent être divisés en 3 catégories:
- modules d'accélérateur : pour courir plus vite que le code Python pur équivalent court en CPython.
- wrapper modules : exposer les interfaces C existantes au code Python.
- low level system access : pour accéder aux fonctionnalités de niveau inférieur de L'exécution CPython, du système d'exploitation, ou du matériel sous-jacent.
afin de donner une perspective plus large à d'autres intéressés et puisque votre question initiale est un peu vague ("à une bibliothèque C ou C++") je pense que cette information pourrait être intéressant pour vous. Sur le lien ci-dessus, vous pouvez lire sur les inconvénients de l'utilisation d'extensions binaires et ses alternatives.
mis à part les autres réponses suggérées, si vous voulez un module accélérateur, vous pouvez essayer Numba . Il fonctionne "en générant un code machine optimisé à l'aide de L'infrastructure de compilateur LLVM au moment de l'importation, à l'exécution, ou statiquement (en utilisant l'outil pycc inclus)".