Cython para envolver el código C existente

¿Qué es Cython?
Es un compilador estático de optimización tanto para el lenguaje de programación Python como para el lenguaje de programación extendido Cython. Se utiliza para facilitar la escritura de extensiones C para Python tan fácilmente como el mismo Python.

Viene con muchas características útiles :

  • Escribir un código de Python que llama de un lado a otro desde y hacia el código C/C++.
  • Fácil ajuste del código Python legible en el rendimiento C simple mediante la adición de declaraciones de tipo estático.
  • Uso de depuración de nivel de código fuente combinado para encontrar errores en código Python, Cython y C dado.
  • Interacción eficiente con grandes conjuntos de datos, por ejemplo, utilizando arrays NumPy multidimensionales.
  • Integración con código y datos existentes de bibliotecas y aplicaciones de bajo nivel o alto rendimiento.

Hacer una extensión con Cython es una tarea difícil de realizar. Al hacerlo, es necesario crear una colección de funciones contenedoras. Suponiendo que el código de trabajo que se muestra se haya compilado en una biblioteca C llamada libwork . El siguiente código creará un archivo llamado csample.pxd.

Código #1:

# cwork.pxd
#
# Declarations of "external" C 
# functions and structures
  
cdef extern from "work.h":
   
    int gcd(int, int)
    int divide(int, int, int *)
    double avg(double *, int) nogil
      
    ctypedef struct Point:
        double x
        double y
          
    double distance(Point *, Point *)

En Cython, el código anterior funcionará como un archivo de encabezado C. La declaración inicial cdef extern from "work.h"declara el archivo de encabezado C requerido. Las declaraciones que siguen se toman del encabezado. El nombre de este archivo es cwork.pxd. El siguiente objetivo es crear un work.pyxarchivo que definirá contenedores que conecten el intérprete de Python con el código C subyacente declarado en el cwork.pxdarchivo.

Código #2:

# work.pyx
# Import the low-level C declarations
        
cimport cwork
# Importing functionalities from Python
# and the C stdlib
from cpython.pycapsule cimport * 
from libc.stdlib cimport malloc, free
  
# Wrappers
def gcd(unsigned int x, unsigned int y):
    return cwork.gcd(x, y)
  
def divide(x, y):
    cdef int rem
    quot = cwork.divide(x, y, &rem)
    return quot, rem
  
def avg(double[:] a):
    cdef:
        int sz
        double result
  
    sz = a.size
  
    with nogil:
        result = cwork.avg(<double *> &a[0], sz)
  
    return result

 
Código #3:

# Destructor for cleaning up Point objects
cdef del_Point(object obj):
    pt = <csample.Point *> PyCapsule_GetPointer(obj, "Point")
    free(<void *> pt)
      
# Create a Point object and return as a capsule
def Point(double x, double y):
    cdef csample.Point * p
    p = <csample.Point *> malloc(sizeof(csample.Point))
      
    if p == NULL:
        raise MemoryError("No memory to make a Point")
          
    p.x = x
    p.y = y
      
    return PyCapsule_New(<void *>p, "Point",
                         <PyCapsule_Destructor>del_Point)
  
def distance(p1, p2):
    pt1 = <csample.Point *> PyCapsule_GetPointer(p1, "Point")
    pt2 = <csample.Point *> PyCapsule_GetPointer(p2, "Point")
      
    return csample.distance(pt1, pt2)

 
Finalmente, para construir el módulo de extensión, cree un work.pyarchivo.

Código #4:

# importing libraries
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
  
ext_modules = [Extension('work', 
                         ['work.pyx'], 
                         libraries=['work'], 
                         library_dirs=['.'])]
  
setup(name = 'work extension module',
      cmdclass = {'build_ext': build_ext},
      ext_modules = ext_modules)

 
Código #5: Construcción del módulo resultante para la experimentación.

bash % python3 setup.py build_ext --inplace
running build_ext
  
cythoning work.pyx to work.c
building 'work' extension
  
gcc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
-I/usr/local/include/python3.3m -c work.c
-o build/temp.macosx-10.6-x86_64-3.3/work.o
  
gcc -bundle -undefined dynamic_lookup build/temp.macosx-10.6-x86_64-3.3/work.o
-L. -lwork -o work.so
bash %

Ahora, tenemos un módulo de extensión work.so. Vamos a ver cómo funciona.

Código #6:

import sample
print ("GCD : ", sample.gcd(12, 8))
  
print ("\nDivision : ", sample.divide(42,10))
  
import array
arr = array.array('d',[1,2,3])
print ("\nAverage  : ", sample.avg(a)
  
pt1 = sample.Point(2,3)
pt2 = sample.Point(4,5)
  
print ("\npt1 : ", pt1)
print ("\npt2 : ", pt2)
  
print ("\nDistance between the two points : ", 
       sample.distance(pt1, pt2))

Producción :

GCD : 4

Division : (4, 2)

Average : 2.0

pt1 : <capsule object "Point" at 0x1005d1e70>

pt2 : <capsule object "Point" at 0x1005d1ea0>

Distance between the two points : 2.8284271247461903

En un alto nivel, el uso de Cython sigue el modelo de C. Los archivos .pxd simplemente contienen definiciones de C (similares a .hlos archivos) y los .pyxarchivos contienen implementación (similar a un .carchivo). Cython utiliza la instrucción cimport para importar definiciones desde un .pxdarchivo. Esto es diferente a usar una declaración de importación de Python normal, que cargaría un módulo de Python normal.

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 *