Módulo de extensión C usando Python

Escribir un módulo de extensión C simple directamente usando la API de extensión de Python y ninguna otra herramienta. Es sencillo hacer un módulo de extensión hecho a mano para un código C simple. Pero primero, debemos asegurarnos de que el código C tenga un archivo de encabezado adecuado.

Código #1:

#include <math.h>
  
extern int gcd(int, int);
extern int in_mandel(double x0, double y0, int n);
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);

 
El encabezado correspondería a una biblioteca que se ha compilado por separado. El siguiente código ilustra los conceptos básicos para escribir funciones de extensión, siguiendo esta suposición.

Código #2:

# include "Python.h"
# include "sample.h"
  
/* int gcd(int, int) */
static PyObject * py_gcd(PyObject * self, PyObject * args)
{
    int x, y, result;
    if (! PyArg_ParseTuple(args, "ii", &x, &y))
    {
        return NULL;
    }
    result = gcd(x, y);
    return Py_BuildValue("i", result);
}
  
/* int divide(int, int, int *) */
static PyObject * py_divide(PyObject * self, PyObject * args)
{
    int a, b, quotient, remainder;
    if (! PyArg_ParseTuple(args, "ii", &a, &b))
    {
        return NULL;
    }
    quotient = divide(a, b, &remainder);
    return Py_BuildValue("(ii)", quotient, remainder);
}

 
Código #3: tabla y estructura del método del módulo

/* Module method table */
static PyMethodDef SampleMethods[] =
{
    {"gcd", py_gcd, METH_VARARGS, "Greatest common divisor"},
    {"divide", py_divide, METH_VARARGS, "Integer division"},
    { NULL, NULL, 0, NULL}
};
  
/* Module structure */
static struct PyModuleDef samplemodule =
{
    PyModuleDef_HEAD_INIT,
    "sample", /* name of module */
    "A sample module", /* Doc string (may be NULL) */
    -1, /* Size of per-interpreter state or -1 */
    SampleMethods /* Method table */
};
  
/* Module initialization function */
PyMODINIT_FUNC
PyInit_sample(void)
{
    return PyModule_Create(&samplemodule);
}

Código #4: Creando un setup.pyarchivo python para construir el módulo de extensión.

# setup.py
from distutils.core import setup, Extension
  
setup(name='sample',
    ext_modules=[
            Extension('sample',
                    ['pysample.c'],
                    include_dirs = ['/some/dir'],
                    define_macros = [('FOO','1')],
                    undef_macros = ['BAR'],
                    library_dirs = ['/usr/local/lib'],
                    libraries = ['sample']
                    )
            ]
)

Código #5: Ahora simplemente use python3 buildlib.py build_ext --inplace para construir la biblioteca resultante.

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 pysample.c
  -o build/temp.macosx-10.6-x86_64-3.3/pysample.o
gcc -bundle -undefined dynamic_lookup
build/temp.macosx-10.6-x86_64-3.3/pysample.o \
  -L/usr/local/lib -lsample -o sample.so
bash %

El código anterior creará una biblioteca compartida llamada sample.so .
 
Código #6:

import sample
  
print ("gcd = ", sample.gcd(35, 42))
  
print ("\ndistance : ", sample.divide(42, 8))

Producción :

gcd = 7

distance = (5, 2)

 
Extending and Embedding the Python Interpreter es una documentación de Python que se puede consultar antes de intentar cualquier tipo de extensión manuscrita.

En los módulos de extensión, las funciones se pueden escribir como se muestra en el fragmento de código a continuación.

Código #4:

static PyObject *py_func(PyObject *self, PyObject *args)
{
    ...
}
  • PyObject : tipo de datos C que representa cualquier objeto de Python. En un nivel muy alto, una función de extensión es una función de C que recibe una tupla de objetos de Python (en PyObject *args) y, como resultado, devuelve un nuevo objeto de Python. El argumento propio de la función no se usa para funciones de extensión simples, pero entra en juego si desea definir nuevas clases o tipos de objetos en C.
  • La PyArg_ParseTuple()función se usa para convertir valores de Python a una representación C. Como entrada, toma una string de formato que indica los valores requeridos, como «i» para entero y «d» para doble, así como las direcciones de las variables C en las que colocar los resultados convertidos.
  • Py_BuildValue()La función se utiliza para crear objetos Python a partir de tipos de datos C. También acepta un código de formato para indicar el tipo deseado. En las funciones de extensión, se usa para devolver los resultados a Python. Una característica de Py_BuildValue()es que puede construir tipos de objetos más complicados, como tuplas y diccionarios.

Publicación traducida automáticamente

Artículo escrito por manikachandna97 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *