Importar constantes de archivo .h en python

He estado buscando una respuesta simple a esta pregunta, pero parece que no puedo encontrar una. Preferiría mantenerme alejado de cualquier biblioteca externa que no esté incluida en Python 2.6 / 2.7.

Tengo 2 archivos de cabecera c que se parecen a los siguientes:

//constants_a.h const double constant1 = 2.25; const double constant2 = -0.173; const int constant3 = 13; 

 //constants_b.h const double constant1 = 123.25; const double constant2 = -0.12373; const int constant3 = 14; 

Y tengo una clase de python en la que quiero importar estas constantes:

     #pythonclass.py class MyObject(object): def __init(self, mode): if mode is "a": # import from constants_a.h, like: # self.constant1 = constant1 # self.constant2 = constant2 elif mode is "b": # import from constants_b.h, like: # self.constant1 = constant1 # self.constant2 = constant2 

    Tengo un código c que usa las constantes también, y se parece a esto:

     //computations.c #include  #include  #include "constants_a.h" // do some calculations, blah blah blah 

    ¿Cómo puedo importar las constantes del archivo de encabezado a la clase Python?

    La razón de los archivos de encabezado constants_a.h y constants_b.h es que estoy usando python para hacer la mayoría de los cálculos usando las constantes, pero en un momento necesito usar C para hacer cálculos más optimizados. En este punto, estoy usando ctypes para envolver el código c en Python. Quiero mantener las constantes alejadas del código en caso de que necesite actualizarlas o cambiarlas, y hacer que mi código sea mucho más limpio también. No sé si es útil tener en cuenta que también estoy usando NumPy, pero aparte de eso, no hay otras extensiones Python no estándar. También estoy abierto a cualquier sugerencia sobre el diseño o la architecture de este progtwig.

    Recomiendo usar expresiones regulares ( re módulo) para analizar la información que desea de los archivos.

    La construcción de un analizador de C completo sería enorme, pero si solo utiliza las variables y el archivo es razonablemente simple / predecible / bajo control, entonces lo que necesita escribir es sencillo.

    ¡Sólo tenga cuidado con los artefactos ‘gotcha’, como el código comentado!

    En general, la definición de variables en el archivo de encabezado C es un estilo pobre. El archivo de encabezado solo debe declarar objetos, dejando su definición para el archivo de código fuente “.c” apropiado.

    Una cosa que querrás hacer es declarar las constantes globales de la biblioteca como extern const whatever_type_t foo; y defina (o “implemente”) ellos (es decir, asignándoles valores) en algún lugar de su código C (asegúrese de hacerlo solo una vez).

    De todos modos, ignoremos cómo lo haces. Supongamos que ya ha definido las constantes y ha hecho visibles sus símbolos en su archivo de objeto compartido “libfoo.so”. Supongamos que desea acceder al símbolo pi , definido como extern const double pi = 3.1415926; En libfoo, desde tu código de Python.

    Ahora normalmente carga su archivo de objeto en Python usando ctypes como este:

     >>> import ctypes >>> libfoo = ctypes.CDLL("path/to/libfoo.so") 

    Pero luego verás que ctypes piensa que libfoo.pi es una función, ¡no un símbolo para datos constantes!

     >>> libfoo.pi <_funcptr object at 0x1c9c6d0> 

    Para acceder a su valor, tiene que hacer algo bastante incómodo: emitir lo que ctypes cree que es una función para volver a un número.

     >>> pi = ctypes.cast(foo.pi, ctypes.POINTER(ctypes.c_double)) >>> pi.contents.value 3.1415926 

    En la jerga C, esto corresponde vagamente a lo siguiente: Tiene un const double pi , pero alguien le obliga a usarlo solo a través de un puntero de función:

     typedef int (*view_anything_as_a_function_t)(void); view_anyting_as_a_function_t pi_view = π 

    ¿Qué haces con el puntero pi_view para usar el valor de pi ? Lo vuelves a convertir como const double * y lo eliminas: *(const double *)(pi_view) .

    Así que todo esto es muy incómodo. Tal vez me esté faltando algo, pero creo que esto se debe al diseño del módulo ctypes , principalmente para realizar llamadas a funciones externas , no para acceder a datos “extranjeros”. Y la exportación de símbolos de datos puros en una biblioteca cargable es posiblemente rara.

    Y esto no funcionará si las constantes son solo definiciones de macro C. En general, no hay forma de acceder externamente a datos definidos por macros. Se expanden en macro en el momento de la comstackción, sin dejar ningún símbolo visible en el archivo de biblioteca generado, a menos que también exporte sus valores de macro en su código C.

    Recomendaría usar algún tipo de archivo de configuración legible tanto para Python como para el progtwig C, en lugar de almacenar valores constantes en los encabezados. Por ejemplo, un simple csv, ini-file o incluso su propio formato simple de pares ‘clave: valor’. Y no habrá necesidad de volver a comstackr el progtwig C cada vez que quieras cambiar uno de los valores 🙂

    Yo votaría Emilio, ¡pero me falta la reputación!

    A pesar de que ha solicitado evitar otras bibliotecas no estándar, puede echar un vistazo a Cython (Cython: C-Extensions para Python http://www.cython.org/), que ofrece la flexibilidad de encoding de Python y la velocidad bruta de ejecución. de C / C ++ – código comstackdo.

    De esta manera, puede usar Python normal para todo, pero manejar los elementos costosos del código usando sus tipos C incorporados. También puede convertir su código Python en archivos .c (o simplemente envolver las bibliotecas C en sí mismas), que luego pueden comstackrse en un binario. He logrado hasta 10x aceleraciones al hacerlo para rutinas numéricas. También creo que NumPy lo usa.