575 votes

Appeler C/C++ depuis Python ?

Quel serait le moyen le plus rapide de construire une liaison Python vers une bibliothèque C ou C++ ?

(J'utilise Windows si cela a de l'importance).

734voto

Florian Bösch Points 12408

ctypes fait partie de la bibliothèque standard, et est donc plus stable et plus largement disponible que le module gorgée qui a toujours eu tendance à me donner problèmes .

Avec ctypes, vous devez satisfaire toute dépendance de python au moment de la compilation, et votre liaison fonctionnera sur tout python possédant ctypes, et pas seulement sur celui contre lequel elle a été compilée.

Supposons que vous ayez une classe d'exemple C++ simple à laquelle vous voulez parler dans un fichier appelé 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 les fournir en les déclarant comme extern "C".

extern "C" {
    Foo* Foo_new(){ return new Foo(); }
    void Foo_bar(Foo* foo){ foo->bar(); }
}

Ensuite, il faut compiler le tout dans 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 enfin, vous devez écrire votre wrapper python (par exemple dans 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 l'avez, vous pouvez l'appeler comme

f = Foo()
f.bar() #and you will see "Hello" on the screen

16 votes

C'est à peu près ce que boost.python fait pour vous en un seul appel de fonction.

229 votes

Ctypes est dans la bibliothèque standard de python, swig et boost ne le sont pas. Swig et boost s'appuient sur des modules d'extension et sont donc liés aux versions mineures de python, ce qui n'est pas le cas des objets partagés indépendants. La construction d'un wrapper de swig ou de boost peut s'avérer pénible, alors que ctypes n'impose aucune condition de construction.

32 votes

Boost repose sur la magie voodoo des templates et un système de construction entièrement personnalisé, ctypes repose sur la simplicité. ctypes est dynamique, boost est statique. ctypes peut gérer différentes versions de bibliothèques. boost ne le peut pas.

192voto

Ralph Points 2537

Vous devriez jeter un coup d'œil à Boost.Python . Voici la courte introduction tirée de leur site web :

La bibliothèque Python de Boost est un cadre permettant d'interfacer Python et C++. Elle vous permet d'exposer rapidement et de manière transparente des classes C++. fonctions et objets C++ à Python, et vice-versa, sans utiliser d'outils spéciaux. outils spéciaux, mais simplement votre compilateur C++. Il est conçu pour envelopper les interfaces C de manière non intrusive, de sorte que vous n'ayez pas à modifier le code C++ pour l'envelopper. C++ pour l'envelopper, ce qui rend Boost.Python idéal pour exposer des bibliothèques bibliothèques tierces à Python. L'utilisation par la bibliothèque de techniques avancées de simplifie sa syntaxe pour les utilisateurs. l'utilisateur, de sorte que le code d'habillage ressemble à une sorte de langage de définition déclaratif (IDL).

1 votes

Boost.Python est l'une des bibliothèques les plus conviviales de Boost. Pour une simple API d'appel de fonction, elle est assez simple et fournit un modèle que vous auriez dû écrire vous-même. C'est un peu plus compliqué si vous voulez exposer une API orientée objet.

22 votes

Boost.Python est la pire chose imaginable. À chaque nouvelle machine et à chaque mise à jour, il s'accompagne de problèmes de liaison.

29 votes

Près de 11 ans plus tard, il est temps de réfléchir à la qualité de cette réponse ?

61voto

Ben Hoffstein Points 44398

La façon la plus rapide de le faire est d'utiliser SWIG .

Exemple de SWIG tutoriel :

/* 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);

Construction d'un module Python sous 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 disposer de python-dev. De plus, sur certains systèmes, les fichiers d'en-tête de python se trouveront dans /usr/include/python2.7, selon la manière dont vous l'avez installé.

Du tutoriel :

SWIG est un compilateur C++ assez complet qui prend en charge presque toutes les fonctionnalités du langage. 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 proxy dans la langue cible - exposant la fonctionnalité sous-jacente d'une manière très naturelle.

0 votes

Pour ceux qui ont ce problème <Python.h> not found vous devez faire gcc $(pkg-config --cflags python3) -fPIC -c example.c example_wrap.c -I/usr/local/include/python3.10 .

55voto

Antonello Points 125

J'ai commencé mon voyage dans la liaison Python <-> C++ à partir de cette page, avec pour objectif de lier des types de données de haut niveau (vecteurs STL multidimensionnels avec des listes Python) :-)

Ayant essayé les solutions basées sur les deux ctypes y boost.python (et n'étant pas ingénieur en logiciel), je les ai trouvés complexes lorsque la liaison de types de données de haut niveau est requise, tandis 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 également).

L'objectif est de rendre une fonction C++ disponible pour Python qui prend une matrice sous forme de vecteur STL 2D et renvoie une moyenne de chaque ligne (sous forme de vecteur STL 1D).

Le code en C++ ("code.cpp") est le suivant :

#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;
}

L'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 ensuite un Fichier de définition d'interface 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 d'interface C++ à partir du fichier de définition d'interface SWIG .

swig -c++ -python code.i

Enfin, nous compilons le fichier source de l'interface C++ générée et lions le tout pour générer une bibliothèque partagée directement importable par Python (le "_" importe) :

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

0 votes

Un cas réel d'implémentation où dans le code C++ les vecteurs stl sont passés comme des références non constantes et donc disponibles pour python comme paramètres de sortie : lobianco.org/antonello/personal:portfolio:portopt

30voto

Jason Baker Points 56682

Vérifiez pyrex o cython . Ce sont des langages de type python pour l'interface entre C/C++ et python.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X