Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Industrial programming >> python

Python - Programación de extensiones con C

Página anteriorPágina siguiente

Cualquier código que escriba usando cualquier lenguaje compilado como C, C++ o Java puede integrarse o importarse a otra secuencia de comandos de Python. Este código se considera una "extensión".

Un módulo de extensión de Python no es más que una biblioteca C normal. En las máquinas Unix, estas bibliotecas suelen terminar en .so (para objeto compartido). En las máquinas con Windows, normalmente verá .dll (para biblioteca enlazada dinámicamente).

Requisitos previos para escribir extensiones

Para comenzar a escribir su extensión, necesitará los archivos de encabezado de Python.

Además, se supone que tiene un buen conocimiento de C o C++ para escribir cualquier extensión de Python usando programación en C.

Primer vistazo a una extensión de Python

Para su primer vistazo a un módulo de extensión de Python, necesita agrupar su código en cuatro partes −

El archivo de encabezado Python.h

Necesitas incluir Python.h archivo de encabezado en su archivo fuente C, que le da acceso a la API interna de Python utilizada para conectar su módulo al intérprete.

Asegúrese de incluir Python.h antes de cualquier otro encabezado que pueda necesitar. Debe seguir los include con las funciones que desea llamar desde Python.

Las funciones de C

Las firmas de la implementación C de sus funciones siempre toma una de las siguientes tres formas:

static PyObject *MyFunction( PyObject *self, PyObject *args );

static PyObject *MyFunctionWithKeywords(PyObject *self,
                                 PyObject *args,
                                 PyObject *kw);

static PyObject *MyFunctionWithNoArgs( PyObject *self );

Cada una de las declaraciones anteriores devuelve un objeto de Python. No existe tal cosa como un vacío en Python como en C. Si no desea que sus funciones devuelvan un valor, devuelva el equivalente en C de Ninguno de Python valor. Los encabezados de Python definen una macro, Py_RETURN_NONE, que hace esto por nosotros.

Los nombres de sus funciones C pueden ser los que desee, ya que nunca se ven fuera del módulo de extensión. Se definen como estáticos función.

Sus funciones C generalmente se nombran combinando el módulo de Python y los nombres de las funciones, como se muestra aquí −

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

Esta es una función de Python llamada func dentro del módulo módulo . Colocará punteros a sus funciones C en la tabla de métodos para el módulo que generalmente viene a continuación en su código fuente.

La tabla de asignación de métodos

Esta tabla de métodos es una matriz simple de estructuras PyMethodDef. Esa estructura se parece a esto −

struct PyMethodDef {
   char *ml_name;
   PyCFunction ml_meth;
   int ml_flags;
   char *ml_doc;
};

Aquí está la descripción de los miembros de esta estructura −

Esta tabla debe terminar con un centinela que consta de valores NULL y 0 para los miembros apropiados.

Ejemplo

Para la función definida anteriormente, tenemos la siguiente tabla de mapeo de métodos −

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

La función de inicialización

La última parte de su módulo de extensión es la función de inicialización. El intérprete de Python llama a esta función cuando se carga el módulo. Se requiere que la función se llame initModule , donde Módulo es el nombre del módulo.

La función de inicialización debe exportarse desde la biblioteca que construirá. Los encabezados de Python definen PyMODINIT_FUNC para incluir los encantamientos apropiados para que eso suceda en el entorno particular en el que estamos compilando. Todo lo que tiene que hacer es usarlo al definir la función.

Su función de inicialización de C generalmente tiene la siguiente estructura general −

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

Aquí está la descripción de Py_InitModule3 función −

Juntar todo esto se parece a lo siguiente −

#include <Python.h>

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

Ejemplo

Un ejemplo simple que hace uso de todos los conceptos anteriores −

#include <Python.h>

static PyObject* helloworld(PyObject* self) {
   return Py_BuildValue("s", "Hello, Python extensions!!");
}

static char helloworld_docs[] =
   "helloworld( ): Any message you want to put here!!\n";

static PyMethodDef helloworld_funcs[] = {
   {"helloworld", (PyCFunction)helloworld, 
      METH_NOARGS, helloworld_docs},
      {NULL}
};

void inithelloworld(void) {
   Py_InitModule3("helloworld", helloworld_funcs,
                  "Extension module example!");
}

Aquí el Py_BuildValue La función se utiliza para construir un valor de Python. Guarde el código anterior en el archivo hello.c. Veríamos cómo compilar e instalar este módulo para ser llamado desde el script de Python.

Creación e instalación de extensiones

Las distutils El paquete hace que sea muy fácil distribuir módulos Python, tanto Python puro como módulos de extensión, de forma estándar. Los módulos se distribuyen en forma de código fuente y se construyen e instalan a través de un script de instalación generalmente llamado setup.py de la siguiente manera.

Para el módulo anterior, debe preparar el siguiente script setup.py −

from distutils.core import setup, Extension
setup(name='helloworld', version='1.0',  \
      ext_modules=[Extension('helloworld', ['hello.c'])])

Ahora, use el siguiente comando, que realizaría todos los pasos necesarios de compilación y vinculación, con los comandos e indicadores correctos del compilador y del vinculador, y copiará la biblioteca dinámica resultante en un directorio apropiado:

$ python setup.py install

En los sistemas basados ​​en Unix, lo más probable es que necesite ejecutar este comando como root para tener permisos para escribir en el directorio de paquetes del sitio. Esto normalmente no es un problema en Windows.

Importación de extensiones

Una vez que haya instalado su extensión, podrá importar y llamar a esa extensión en su secuencia de comandos de Python de la siguiente manera −

#!/usr/bin/python
import helloworld

print helloworld.helloworld()

Esto produciría el siguiente resultado −

Hello, Python extensions!!

Pasar parámetros de función

Como lo más probable es que desee definir funciones que acepten argumentos, puede usar una de las otras firmas para sus funciones C. Por ejemplo, la siguiente función, que acepta una cierta cantidad de parámetros, se definiría así −

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Parse args and do something interesting here. */
   Py_RETURN_NONE;
}

La tabla de métodos que contiene una entrada para la nueva función se vería así −

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { "func", module_func, METH_VARARGS, NULL },
   { NULL, NULL, 0, NULL }
};

Puede utilizar la API PyArg_ParseTuple para extraer los argumentos del puntero PyObject pasado a su función C.

El primer argumento de PyArg_ParseTuple es el argumento args. Este es el objeto que analizará . El segundo argumento es una cadena de formato que describe los argumentos tal como espera que aparezcan. Cada argumento está representado por uno o más caracteres en la cadena de formato de la siguiente manera.

static PyObject *module_func(PyObject *self, PyObject *args) {
   int i;
   double d;
   char *s;

   if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) {
      return NULL;
   }
   
   /* Do something interesting here. */
   Py_RETURN_NONE;
}

Compilar la nueva versión de su módulo e importarlo le permite invocar la nueva función con cualquier número de argumentos de cualquier tipo −

module.func(1, s="three", d=2.0)
module.func(i=1, d=2.0, s="three")
module.func(s="three", d=2.0, i=1)

Probablemente puedas encontrar incluso más variaciones.

La PyArg_ParseTuple Función

Esta es la firma estándar para PyArg_ParseTuple función −

int PyArg_ParseTuple(PyObject* tuple,char* format,...)

Esta función devuelve 0 para errores y un valor distinto de 0 para éxito. tuple es el PyObject* que fue el segundo argumento de la función C. Aquí formato es una cadena C que describe argumentos obligatorios y opcionales.

Aquí hay una lista de códigos de formato para PyArg_ParseTuple función −

Código Tipo C Significado
c carácter Una cadena Python de longitud 1 se convierte en un carácter C.
d doble Un flotante de Python se convierte en un doble de C.
f flotante Un flotante de Python se convierte en un flotante de C.
i int Un int de Python se convierte en un int de C.
l largo Un Python int se convierte en un C long.
L largo largo Un Python int se convierte en un C long long
O PyObjeto* Obtiene una referencia prestada no NULL al argumento de Python.
s char* Cadena de Python sin valores nulos incrustados en C char*.
s# char*+int Cualquier cadena de Python a dirección C y longitud.
t# char*+int Búfer de un solo segmento de solo lectura para dirección C y longitud.
u Py_UNICODE* Python Unicode sin valores nulos incrustados en C.
u# Py_UNICODE*+int Cualquier dirección y longitud de Python Unicode C.
w# char*+int Lectura/escritura de búfer de segmento único en dirección C y longitud.
z char* Al igual que s, también acepta Ninguno (establece C char* en NULL).
z# char*+int Al igual que s#, también acepta Ninguno (establece C char* en NULL).
(...) según... Una secuencia de Python se trata como un argumento por elemento.
| Los siguientes argumentos son opcionales.
: Fin del formato, seguido del nombre de la función para los mensajes de error.
; Fin del formato, seguido del texto completo del mensaje de error.

Valores devueltos

Py_BuildValue toma una cadena de formato muy parecida a PyArg_ParseTuple lo hace. En lugar de pasar las direcciones de los valores que está creando, pasa los valores reales. Aquí hay un ejemplo que muestra cómo implementar una función de suma −

static PyObject *foo_add(PyObject *self, PyObject *args) {
   int a;
   int b;

   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("i", a + b);
}

Así es como se vería si se implementara en Python −

def add(a, b):
   return (a + b)

Puede devolver dos valores de su función de la siguiente manera, esto se capturaría usando una lista en Python.

static PyObject *foo_add_subtract(PyObject *self, PyObject *args) {
   int a;
   int b;

   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("ii", a + b, a - b);
}

Así es como se vería si se implementara en Python −

def add_subtract(a, b):
   return (a + b, a - b)

El Py_BuildValue Función

Esta es la firma estándar para Py_BuildValue función −

PyObject* Py_BuildValue(char* format,...)

Aquí formato es una cadena C que describe el objeto de Python a construir. Los siguientes argumentos de Py_BuildValue son valores de C a partir de los cuales se construye el resultado. El PyObjeto* el resultado es una nueva referencia.

La siguiente tabla enumera las cadenas de código de uso común, de las cuales cero o más se unen en formato de cadena.

Código Tipo C Significado
c carácter Un carácter C se convierte en una cadena Python de longitud 1.
d doble Un doble C se convierte en un flotante de Python.
f flotante Un flotante de C se convierte en un flotante de Python.
i int Un int de C se convierte en un int de Python.
l largo A C long se convierte en Python int.
N PyObjeto* Pasa un objeto Python y roba una referencia.
O PyObjeto* Pasa un objeto de Python y lo incrementa como de costumbre.
O& convertir+vacío* Conversión arbitraria
s char* C char terminado en 0* a cadena Python, o NULL a Ninguno.
s# char*+int Carácter C* y longitud a cadena Python, o NULL a Ninguno.
u Py_UNICODE* Cadena de ancho C, terminada en nulo a Python Unicode, o NULL a Ninguno.
u# Py_UNICODE*+int Cadena de ancho C y longitud a Python Unicode, o NULL a Ninguno.
w# char*+int Lectura/escritura de búfer de segmento único en dirección C y longitud.
z char* Al igual que s, también acepta Ninguno (establece C char* en NULL).
z# char*+int Al igual que s#, también acepta Ninguno (establece C char* en NULL).
(...) según... Construye una tupla de Python a partir de valores C.
[...] según... Construye una lista de Python a partir de valores C.
{...} según... Construye el diccionario de Python a partir de valores C, alternando claves y valores.

Code {...} crea diccionarios a partir de un número par de valores de C, alternativamente claves y valores. Por ejemplo, Py_BuildValue("{issi}",23,"zig","zag",42) devuelve un diccionario como {23:'zig','zag':42} de Python.


python

  1. Programación orientada a objetos de Python
  2. Declaración Python Print():cómo imprimir con ejemplos
  3. Python String strip() Función con EJEMPLO
  4. Python String count () con EJEMPLOS
  5. Python String format() Explicar con EJEMPLOS
  6. Método Python String find() con ejemplos
  7. Funciones Python Lambda con EJEMPLOS
  8. Función Python round() con EJEMPLOS
  9. Función Python map() con EJEMPLOS
  10. Python Timeit() con ejemplos
  11. Contador de Python en colecciones con ejemplo