Usando códigos C en Python | Serie 1

Requisito previo: cómo llamar a una función C en Python

Analicemos el problema de acceder al código C desde Python. Como es muy evidente, muchas de las bibliotecas integradas de Python están escritas en C. Por lo tanto, acceder a C es una parte muy importante para hacer que Python se comunique con las bibliotecas existentes. Hay una extensa API de programación C que proporciona Python, pero hay muchas diferentes para tratar con C.

Código #1: [ work.c] C-Code que estamos tratando.

#include <math.h>
  
int gcd(int x, int y)
{
    int g = y;
    while (x > 0)
    {
        g = x;
        x = y % x;
        y = g;
    }
    return g;
}
  
int divide(int a, int b, int * remainder)
{
    int quot = a / b;
    *remainder = a % b;
    return quot;
}
  
double avg(double * a, int n)
{
    int i;
    double total = 0.0;
    for (i = 0; i < n; i++)
    {
        total += a[i];
    }
    return total / n;
}
  
typedef struct Point
{
    double x, y;
} Point;
  
double distance(Point * p1, Point * p2)
{
    return hypot(p1->x - p2->x, p1->y - p2->y);
}

El código anterior tiene diferentes características de programación C.

gcd()
divide(): devuelve varios valores, uno a través de un argumento de puntero
avg(): realiza una reducción de datos en una array C
Punto y distancia(): involucra estructuras C.

Supongamos que el código anterior se encuentra en un archivo llamado work.c y se ha compilado en una biblioteca libsample que se puede vincular a otro código C. Ahora, tenemos varias funciones de C que se han compilado en una biblioteca compartida. Por lo tanto, llamamos a las funciones completamente desde Python sin tener que escribir código C adicional o usar una herramienta de extensión de terceros.
 
Uso de ctypes: los ctypes
de Python entrarán en juego, pero asegúrese de que el código C, que se va a convertir, se haya compilado en una biblioteca compartida que sea compatible con el intérprete de Python (por ejemplo, la misma arquitectura, tamaño de palabra, compilador, etc.) .

Además, el archivo libsample.so se ha colocado en el mismo directorio que el archivo work.py. Entendamos work.pyahora.

Código n.º 2: módulo de Python que envuelve la biblioteca resultante para acceder a ella

# work.py
import ctypes
import os
  
# locating the 'libsample.so' file in the
# same directory as this file
_file = 'libsample.so'
_path = os.path.join(*(os.path.split(__file__)[:-1] + (_file, )))
_mod = ctypes.cdll.LoadLibrary(_path)

Código #3: Código de acceso

# int gcd(int, int)
gcd = _mod.gcd
gcd.argtypes = (ctypes.c_int, ctypes.c_int)
gcd.restype = ctypes.c_int
  
# int divide(int, int, int *)
_divide = _mod.divide
_divide.argtypes = (ctypes.c_int, ctypes.c_int,
                    ctypes.POINTER(ctypes.c_int))
  
_divide.restype = ctypes.c_int
  
def divide(x, y):
    rem = ctypes.c_int()
    quot = _divide(x, y, rem)
    return quot, rem.value
  
# void avg(double *, int n)
# Define a special type for the 'double *' argument
class DoubleArrayType:
    def from_param(self, param):
          
        typename = type(param).__name__
          
        if hasattr(self, 'from_' + typename):
            return getattr(self, 'from_' + typename)(param)
          
        elif isinstance(param, ctypes.Array):
            return param
          
        else:
            raise TypeError("Can't convert % s" % typename)
  
    # Cast from array.array objects
    def from_array(self, param):
        if param.typecode != 'd':
            raise TypeError('must be an array of doubles')
          
        ptr, _ = param.buffer_info()
        return ctypes.cast(ptr, ctypes.POINTER(ctypes.c_double))
          
    # Cast from lists / tuples
    def from_list(self, param):
        val = ((ctypes.c_double)*len(param))(*param)
        return val
      
    from_tuple = from_list
      
    # Cast from a numpy array
    def from_ndarray(self, param):
        return param.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
  
DoubleArray = DoubleArrayType()
_avg = _mod.avg
_avg.argtypes = (DoubleArray, ctypes.c_int)
_avg.restype = ctypes.c_double
  
def avg(values):
    return _avg(values, len(values))
  
# struct Point { }
class Point(ctypes.Structure):
    _fields_ = [('x', ctypes.c_double), ('y', ctypes.c_double)]
      
# double distance(Point *, Point *)
distance = _mod.distance
distance.argtypes = (ctypes.POINTER(Point), ctypes.POINTER(Point))
distance.restype = ctypes.c_double

Ahora, uno puede cargar fácilmente el módulo y usar las funciones C resultantes. Vea la siguiente parte: uso de códigos C en Python | conjunto 2 .

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 *