Requisito previo: Usar códigos C en Python , Envolver C/C++ para Python usando SWIG
Supongamos que hemos proporcionado un código C y es necesario acceder a él como un módulo de extensión C. Entonces, para la tarea dada, se usa Swig Wrapper Generator.
Swig funciona analizando los archivos de encabezado C y creando automáticamente el código de extensión. Primero se necesita el archivo de encabezado C para usar Swig. Proporcione un ejemplo de archivo de encabezado C en el código a continuación.
Código #1:work.h
// work.h # include <math.h> extern int gcd(int, int); extern int divide(int a, int b, int * remainder); extern double avg(double * a, int n); typedef struct Point { double x, y; } Point; extern double distance(Point * p1, Point * p2);
Después de tener el archivo de encabezado, el siguiente paso es escribir un archivo de «interfaz» de Swig. Por convención, estos archivos tienen un sufijo .i y pueden tener un aspecto similar al siguiente.
Código #2: work.i
// work.i - Swig interface % module work % { # include "work.h" % } // Customizations % extend Point { // Constructor for Point objects Point(double x, double y) { Point * p = (Point *) malloc(sizeof(Point)); p->x = x; p->y = y; return p; }; };
Código #3: Mapeo
// Map int * remainder as an output argument %include typemaps.i %apply int * OUTPUT { int * remainder }; // Map the argument pattern (double * a, int n) to arrays %typemap(in) (double * a, int n)(Py_buffer view) { view.obj = NULL; if (PyObject_GetBuffer($input, &view, PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT) == -1) { SWIG_fail; } if (strcmp(view.format, "d") != 0) { PyErr_SetString(PyExc_TypeError, "Expected an array of doubles"); SWIG_fail; } $1 = (double *) view.buf; $2 = view.len / sizeof(double); } % typemap(freearg) (double * a, int n) { if (view$argnum.obj) { PyBuffer_Release(&view$argnum); } }
Una vez que el archivo de interfaz está listo, Swig se invoca como una herramienta de línea de comandos
Código #4:
bash % swig -python -py3 work.i bash %
La salida de swig son dos archivos, work_wrap.c
y work.py
. El archivo work.py es lo que importan los usuarios y el archivo work_wrap.c es un código C que debe compilarse en un módulo de soporte llamado _work
. Se realiza utilizando las mismas técnicas que para los módulos de extensión normales. Por ejemplo, crear un setup.py
archivo como se muestra en el siguiente código:
Código #5:
# setup.py from distutils.core import setup, Extension setup(name='sample', py_modules=['sample.py'], ext_modules=[ Extension( '_sample', ['sample_wrap.c'], include_dirs = [], define_macros = [], undef_macros = [], library_dirs = [], libraries = ['sample'] ) ] )
Código # 6: Compile y pruebe, ejecute python3 en setup.py
bash % python3 setup.py build_ext --inplace running build_ext building '_sample' extension gcc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/usr/local/include/python3.3m -c work_wrap.c -o build/temp.macosx-10.6-x86_64-3.3/work_wrap.o work_wrap.c: In function ‘SWIG_InitializeModule’: work_wrap.c:3589: warning: statement with no effect gcc -bundle -undefined dynamic_lookup build/temp.macosx-10.6-x86_64-3.3/work.o build/temp.macosx-10.6-x86_64-3.3/work_wrap.o -o _work.so -lwork bash %
Después de realizar todas las tareas, podemos usar el módulo de extensión C de una manera muy fácil.
Código #7:
import work print ("GCD : ", work.gcd(12,8)) print ("\nDivision : ", work.divide(42,8)) pt1 = work.Point(2,3) pt2 = work.Point(4,5) print ("\nDistance between pt1 and pt2 : ", work.distance(pt1,pt2)) print ("\nx co-ordinate of pt1 : ", pt1.x) print ("\ny co-ordinate of pt1 : ", pt1.x) import array ar = array.array('d',[2, 4, 6]) print ("\nAverage : ", work.avg(arr))
Producción :
GCD : 4 Divide : [5, 2] Distance between pt1 and pt2 : 2.8284271247461903 Distance between pt1 and pt2 : 2.0 Distance between pt1 and pt2 : 3.0 Average : 4.0
Publicación traducida automáticamente
Artículo escrito por manikachandna97 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA