2008-09-28 17 views

Respuesta

109

Debería echar un vistazo a Boost.Python. Esta es la breve introducción tomado de su página web:

The Boost Python Library is a framework for interfacing Python and C++. It allows you to quickly and seamlessly expose C++ classes functions and objects to Python, and vice-versa, using no special tools -- just your C++ compiler. It is designed to wrap C++ interfaces non-intrusively, so that you should not have to change the C++ code at all in order to wrap it, making Boost.Python ideal for exposing 3rd-party libraries to Python. The library's use of advanced metaprogramming techniques simplifies its syntax for users, so that wrapping code takes on the look of a kind of declarative interface definition language (IDL).

+0

Boost.Python es una de las librerías más fáciles de usar en Boost, para una API de llamada de función simple es bastante sencillo y proporciona un texto repetitivo que deberías escribir tú mismo. Es un poco más complicado si quieres exponer una API orientada a objetos. – jwfearn

41

La forma más rápida de hacerlo es utilizando SWIG.

Ejemplo de TRAGO tutorial: archivo

/* File : example.c */ 
int fact(int n) { 
    if (n <= 1) return 1; 
    else return n*fact(n-1); 
} 

Interfaz:

/* example.i */ 
%module example 
%{ 
/* Put header files here or function declarations like below */ 
extern int fact(int n); 
%} 

extern int fact(int n); 

La construcción de un módulo de Python en 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 

Uso:

>>> import example 
>>> example.fact(5) 
120 

Tenga en cuenta que debe tener python-dev. También en algunos sistemas, los archivos de cabecera de Python estarán en /usr/include/python2.7 según la forma en que lo haya instalado.

Desde el tutorial:

SWIG is a fairly complete C++ compiler with support for nearly every language feature. This includes preprocessing, pointers, classes, inheritance, and even C++ templates. SWIG can also be used to package structures and classes into proxy classes in the target language — exposing the underlying functionality in a very natural manner.

+0

Ejecución en swig: no se puede ejecutar el error de archivo binario con el mismo código. Parece ser un problema de mi parte, pero cualquier sugerencia sería útil. – iDev

+0

@iDev suena como una pregunta separada – Seanny123

13

nunca he usado, pero he oído cosas buenas sobre ctypes. Si intentas usarlo con C++, asegúrate de evadir el cambio de nombre a través del extern "C". Gracias por el comentario, Florian Bösch.

5

Uno de los documentos oficiales de Python contiene detalles sobre extending Python using C/C++. Incluso sin el uso de SWIG, es bastante sencillo y funciona perfectamente en Windows.

24

Consulte pyrex o Cython. Son lenguajes similares a Python para interactuar entre C/C++ y Python.

+0

+1 para Cython! No he probado cffi, así que no puedo decir cuál es mejor, pero tuve muy buenas experiencias con Cython: todavía escribes el código de Python, pero puedes usar C en él. Fue un poco difícil para mí configurar el proceso de compilación con Cython, que luego expliqué en una publicación de blog: http://martinsosic.com/development/2016/02/08/wrapping-c-library-as-python- module.html – Martinsos

443

me gusta mucho ctypes, swig siempre tendían a darme problems. También ctypes tiene la ventaja de que no necesita satisfacer ninguna dependencia de tiempo de compilación en python, y su enlace funcionará en cualquier python que tenga ctypes, no solo aquel contra el que se compiló.

Supongamos que tiene una clase simple de ejemplo de C++ con la que desea hablar en un archivo llamado foo.CPP:

#include <iostream> 

class Foo{ 
    public: 
     void bar(){ 
      std::cout << "Hello" << std::endl; 
     } 
}; 

Desde ctypes sólo pueden hablar con funciones de C, es necesario proporcionar a los declarándolos como extern "C"

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

siguiente que tiene que compilar esto a una biblioteca compartida

g++ -c -fPIC foo.cpp -o foo.o 
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o 

Y por último hay que escribir su envoltorio pitón (por ejemplo, en 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) 

Una vez que tenga que se le puede llamar como

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

Esto es más o menos lo que impulsa.python hace por usted en una sola llamada a función. –

+142

ctypes está en la biblioteca estándar de Python, swig y boost no. Swig y boost dependen de módulos de extensión y, por lo tanto, están vinculados a versiones menores de python que los objetos compartidos independientes no tienen. construir un contenedor o aumentar las envolturas puede ser un problema, ctypes no necesita requisitos de compilación. –

+10

boost se basa en la magia de la plantilla vudú y en un sistema de compilación completamente personalizado, ctypes se basa en la simplicidad. ctypes es dinámico, boost es estático. ctypes puede manejar diferentes versiones de bibliotecas. impulso no puede. –

10

creo CFFI para Python puede ser una opción.

The goal is to call C code from Python. You should be able to do so without learning a 3rd language: every alternative requires you to learn their own language (Cython, SWIG) or API (ctypes). So we tried to assume that you know Python and C and minimize the extra bits of API that you need to learn.

http://cffi.readthedocs.org/en/release-0.7/

+2

Creo que esto solo puede llamar c (no C++), aún +1 (realmente me gusta cffi). –

34

empecé mi viaje en el pitón < -> C++ vinculante de esta página, con el objetivo de vincular los tipos de datos de alto nivel (STL vectores multidimensionales con las listas de Python) :-)

Después de probar las soluciones basadas en ctypes y boost.python (y no ser un ingeniero de software) las encontré complejas cuando se requiere el enlace de tipos de datos de alto nivel, mientras que encontré SWIG mucho más simple para tales casos.

Este ejemplo utiliza, por lo tanto, SWIG, y se ha probado en Linux (pero SWIG está disponible y también se usa ampliamente en Windows).

El objetivo es hacer que una función C++ esté disponible para Python que toma una matriz en forma de un vector 2D STL y devuelve un promedio de cada fila (como un vector 1D STL).

El código en C++ ("code.cpp") es la siguiente:

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

La cabecera equivalente ("code.h") es:

#ifndef _code 
#define _code 

#include <vector> 

std::vector<double> average (std::vector< std::vector<double> > i_matrix); 

#endif 

primera Compilamos el C++ código para crear un archivo de objeto:

g++ -c -fPIC code.cpp 

a continuación, definir un SWIG interface definition file ("code.i") para nuestro C++ funciones.

%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" 

Utilizando SWIG, generamos un código fuente de interfaz C++ desde el archivo de definición de interfaz SWIG.

swig -c++ -python code.i 

Finalmente compilar el archivo fuente de la interfaz generada C++ y enlace todo juntos para generar una biblioteca compartida que es importar directamente por el pitón (los asuntos "_"):

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 

Ahora podemos usar la función en las secuencias de comandos 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

Una implementación de caso real donde en el código C++ los vectores stl se pasan como referencias no const y, por lo tanto, están disponibles por python como parámetros de salida: http://lobianco.org/antonello/personal:portfolio:portopt – Antonello

3

Primero debe decidir cuál es su propósito particular. La documentación oficial de Python en extending and embedding the Python interpreter se mencionó anteriormente, puedo agregar un buen overview of binary extensions. Los casos de uso se pueden dividir en 3 categorías:

  • módulos de acelerador: correr más rápido que el código Python puro equivalente ejecuta en CPython.
  • módulos de contenedor: exponer las interfaces C existentes al código Python.
  • bajo nivel de acceso al sistema: para acceder a las características de nivel inferior del tiempo de ejecución CPython, el sistema operativo o el hardware subyacente.

Para dar una perspectiva más amplia para otros interesados ​​y dado que su pregunta inicial es un poco vaga ("a una biblioteca C o C++"), creo que esta información podría serle interesante. En el enlace de arriba puede leer sobre las desventajas del uso de extensiones binarias y sus alternativas.

Aparte de las otras respuestas sugeridas, si quiere un módulo de acelerador, puede probar Numba. Funciona "generando código de máquina optimizado utilizando la infraestructura del compilador LLVM en tiempo de importación, tiempo de ejecución o estáticamente (utilizando la herramienta pycc incluida)".

4

La pregunta es cómo llamar a una función C desde Python, si entendí correctamente. Entonces, la mejor apuesta es Ctypes (por cierto, portátil en todas las 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 

Para una guía detallada que usted lo desea, puede hacer referencia a my blog article.

+0

Puede valer la pena señalar que, aunque ctypes son portátiles, su código requiere una biblioteca de C específica de Windows. – Palec

4

Cython es definitivamente el camino a seguir, a menos que anticipe escribir envoltorios Java, en cuyo caso puede ser preferible SWIG.

Recomiendo usar la utilidad de línea de comandos runcython, hace que el proceso de uso de Cython sea extremadamente fácil. Si necesita pasar datos estructurados a C++, eche un vistazo a la biblioteca de protobuf de Google, es muy conveniente.

que aquí hay una mínimos ejemplos que hice que utiliza ambas herramientas:

https://github.com/nicodjimenez/python2cpp

esperanza de que puede ser un punto de partida útil.

1

Para C moderna ++, el uso cppyy: http://cppyy.readthedocs.io/en/latest/

Se basa en Cling, el intérprete de C++ para Clang/LLVM. Los enlaces están en tiempo de ejecución y no es necesario un lenguaje intermedio adicional. Gracias a Clang, es compatible con C++ 17.

instalarlo usando pip:

$ pip install cppyy 

Para proyectos pequeños, sólo tiene que cargar la biblioteca relevante y los encabezados de los que está interesado en, por ejemplo. tomar el código del ejemplo ctypes es este hilo, pero dividida en las secciones de cabecera y de código:

$ cat foo.h 
    class Foo { 
    public: 
     void bar(); 
    }; 

    $ cat foo.cpp 
    #include "foo.h" 
    #include <iostream> 

    void Foo::bar() { std::cout << "Hello" << std::endl; } 

compilarlo:

$ g++ -c -fPIC foo.cpp -o foo.o 
    $ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o 

y lo utilizan:

$ python 
    >>> import cppyy 
    >>> cppyy.include("foo.h") 
    >>> cppyy.load_library("foo") 
    >>> from cppyy.gbl import Foo 
    >>> f = Foo() 
    >>> f.bar() 
    Hello 
    >>> 

grandes proyectos son compatible con la carga automática de la información de reflexión preparada y los fragmentos de cmake para crearlos, de modo que los usuarios de los paquetes instalados simplemente puedan ejecutar:

$ python 
    >>> import cppyy 
    >>> f = cppyy.gbl.Foo() 
    >>> f.bar() 
    Hello 
    >>> 

Gracias a LLVM, son posibles funciones avanzadas, como la creación automática de instancias de plantillas. Para continuar con el ejemplo:

>>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]() 
    >>> v.push_back(f) 
    >>> len(v) 
    1 
    >>> v[0].bar() 
    Hello 
    >>> 

Nota: Soy el autor de cppyy.

+0

Si bien este enlace puede responder la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace de referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página vinculada cambia. - [De la crítica] (/ review/low-quality-posts/19014837) – duckmayr

+0

Gracias por los comentarios. Actualicé la respuesta con las instrucciones de instalación y le mostré cómo usar el ejemplo presentado anteriormente en este hilo. –