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 anterior Página siguiente

Cualquier código que escriba utilizando cualquier lenguaje compilado como C, C ++ o Java puede integrarse o importarse en otro script 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 máquinas Unix, estas bibliotecas suelen terminar en .so (para objeto compartido). En máquinas con Windows, normalmente verá .dll (para biblioteca vinculada dinámicamente).

Requisitos previos para las extensiones de escritura

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

Además, se asume 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 ver por primera vez un módulo de extensión de Python, debe 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 las inclusiones con las funciones que desea llamar desde Python.

Las funciones C

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

 PyObject estático * MyFunction (PyObject * self, PyObject * args); PyObject * MyFunctionWithKeywords (PyObject * self, PyObject * args, PyObject * kw); PyObject estático * MyFunctionWithNoArgs * self; 

Cada una de las declaraciones anteriores devuelve un objeto Python. No existe tal cosa como un vacío función 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. Están definidos 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í -

 PyObject estático *  module_func  (PyObject * self, PyObject * args) {/ * Haga sus cosas aquí. * / Py_RETURN_NONE;} 

Esta es una función de Python llamada func dentro del módulo módulo . Pondrá punteros a sus funciones C en la tabla de métodos para el módulo que normalmente 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 terminarse 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:

 módulo estático PyMethodDef   _methods [] ={{" func  ", (PyCFunction)  módulo_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 init Módulo , donde Módulo es el nombre del módulo.

La función de inicialización debe exportarse desde la biblioteca que creará. Los encabezados de Python definen PyMODINIT_FUNC para incluir los encantamientos apropiados para que eso suceda para 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 init  Módulo  () {Py_InitModule3 ( función  ,  módulo  _methods, "docstring ...");} 

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

Poner todo esto junto se parece a lo siguiente:

 # incluye  PyObject estático *  module_func  (PyObject * self, PyObject * args) {/ * Haga sus cosas aquí. * / Py_RETURN_NONE;} módulo estático PyMethodDef   _methods [] ={{" func  ", (PyCFunction)  módulo_func  , METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}}; PyMODINIT_FUNC init  Módulo  () {Py_InitModule3 ( función  ,  módulo  _methods, "docstring ...");} 

Ejemplo

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

 # include  static PyObject * helloworld (PyObject * self) {return Py_BuildValue ("s", "Hola, extensiones de Python !!");} static char helloworld_docs [] ="helloworld ():¡¡Cualquier mensaje que quieras poner aquí !! \ n"; static PyMethodDef helloworld_funcs [] ={{"helloworld", (PyCFunction) helloworld, METH_NOARGS, helloworld_docs}, {NULL}}; void inithelloworld (void) {Py_InitModule3 ("helloworld", helloworld_funcs, "¡Ejemplo de módulo de extensión!");} 

Aquí el Py_BuildValue La función se usa 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 hace que sea muy fácil distribuir módulos de 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 mediante un script de configuración normalmente llamado setup.py de la siguiente manera.

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

 de la configuración de importación distutils.core, Extensionsetup (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 copie la biblioteca dinámica resultante en un directorio apropiado:

 $ python setup.py instalar 

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 site-packages. Por lo general, esto 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 / pythonimport helloworldprint helloworld.helloworld () 

Esto produciría el siguiente resultado:

 ¡Hola, extensiones de Python! 

Pasar parámetros de función

Como probablemente querrá definir funciones que acepten argumentos, puede usar una de las otras firmas para sus funciones C. Por ejemplo, la siguiente función, que acepta cierto número de parámetros, se definiría así:

 PyObject estático *  module_func  (PyObject * self, PyObject * args) {/ * Analiza argumentos y haz algo interesante aquí. * / Py_RETURN_NONE;} 

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

 módulo estático PyMethodDef   _methods [] ={{" func  ", (PyCFunction)  módulo_func  , METH_NOARGS, NULL}, {" func  ",  módulo_func  , METH_VARARGS, NULL}, {NULL, NULL, 0, NULL}}; 

Puede utilizar API PyArg_ParseTuple función 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 estará analizando . El segundo argumento es una cadena de formato que describe los argumentos como espera que aparezcan. Cada argumento está representado por uno o más caracteres en la cadena de formato de la siguiente manera.

 PyObject estático *  module_func  (PyObject * self, PyObject * args) {int i; doble d; char * s; if (! PyArg_ParseTuple (args, "ids", &i, &d, &s)) {return NULL; } / * Haz algo interesante aquí. * / Py_RETURN_NONE;} 

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

 módulo.func (1, s ="tres", d =2.0) módulo.func (i =1, d =2.0, s ="tres") módulo.func (s =" tres ", d =2.0, i =1) 

Probablemente se le ocurran incluso más variaciones.

El PyArg_ParseTuple Función

Aquí está la firma estándar para PyArg_ParseTuple función -

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

Esta función devuelve 0 para errores y un valor no igual a 0 para éxito. tuple es el PyObject * que era 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 char Una cadena de Python de longitud 1 se convierte en un carácter C.
d doble Un flotador de Python se convierte en un doble de C.
f flotar Un flotador Python se convierte en un flotador C.
i int Un int de Python se convierte en un int de C.
l largo Un Python int se convierte en C largo.
L largo largo Un Python int se convierte en un C long long
O PyObject * Obtiene una referencia prestada no NULL al argumento de Python.
s char * Cadena de Python sin nulos incrustados en C char *.
s # char * + int Cualquier cadena de Python a la dirección y longitud de C.
t # char * + int Búfer de segmento único de solo lectura a la dirección y longitud C.
u Py_UNICODE * Python Unicode sin 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 y longitud C.
z char * Como s, también acepta None (establece C char * en NULL).
z # char * + int Como s #, también acepta None (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.

Devolución de valores

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á construyendo, pasa los valores reales. A continuación, se muestra un ejemplo que muestra cómo implementar una función de adición:

 PyObject estático * 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.

 PyObject estático * 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

Aquí está la firma estándar para Py_BuildValue función -

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

Aquí formato es una cadena C que describe el objeto Python que se va a construir. Los siguientes argumentos de Py_BuildValue son valores de C a partir de los cuales se construye el resultado. El PyObject * 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 char Un carácter C se convierte en una cadena de Python de longitud 1.
d doble Un doble de C se convierte en un flotante de Python.
f flotar Un flotador C se convierte en un flotador Python.
i int Un C int se convierte en un Python int.
l largo A C de largo se convierte en Python int.
N PyObject * Pasa un objeto Python y roba una referencia.
O PyObject * Pasa un objeto Python y lo INCREF como normal.
O & convertir + void * Conversión arbitraria
s char * C 0-terminado char * a cadena de Python, o NULL a Ninguno.
s # char * + int C char * y longitud en cadena Python, o NULL en None.
u Py_UNICODE * Cadena C-wide, terminada en nulo a Python Unicode, o NULL a Ninguno.
u # Py_UNICODE * + int Cadena de ancho C y longitud para Python Unicode, o NULL para Ninguno.
w # char * + int Lectura / escritura de búfer de segmento único en dirección y longitud C.
z char * Como s, también acepta None (establece C char * en NULL).
z # char * + int Como s #, también acepta None (establece C char * en NULL).
(...) según ... Crea una tupla de Python a partir de valores C.
[...] según ... Crea una lista de Python a partir de valores C.
{...} según ... Crea un diccionario Python a partir de valores C, alternando claves y valores.

Code {...} construye diccionarios a partir de un número par de valores 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. Formato de cadena de Python () Explique con EJEMPLOS
  2. Migrar a Python 3
  3. Python - Sintaxis básica
  4. Cómo no manejar excepciones en Python
  5. Método readline () de Python con ejemplos
  6. Conversión y conversión de tipos de Python