2013-03-08 9 views
14

Ho cercato una risposta semplice a questa domanda, ma sembra che non riesca a trovarne una. Preferirei stare lontano da qualsiasi libreria esterna che non sia già inclusa in Python 2.6/2.7.Importare le costanti dal file .h in python

ho 2 file header C analoghi ai seguenti:

//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; 

...

E ho una classe di pitone che voglio importare queste costanti in:

#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 

...

Ho codice C che utilizza le costanti come bene, e assomiglia a questo:

//computations.c 
#include <stdio.h> 
#include <math.h> 
#include "constants_a.h" 

// do some calculations, blah blah blah 

Come posso importare le costanti dal file di intestazione nella classe Python?

Il motivo per i file di intestazione constants_a.h e constants_b.h è che sto usando python per fare la maggior parte dei calcoli usando le costanti, ma a un certo punto ho bisogno di usare C per fare calcoli più ottimizzati. A questo punto sto usando i ctype per avvolgere il codice c in Python. Voglio mantenere le costanti lontane dal codice solo nel caso in cui avessi bisogno di aggiornarle o modificarle, e rendere il mio codice molto più pulito. Non so se è utile notare che sto usando anche NumPy, ma a parte questo, nessun'altra estensione Python non standard. Sono inoltre aperto a qualsiasi suggerimento riguardante il design o l'architettura di questo programma.

+0

Ci scusiamo per il feedback tardivo di tutti. Avevo un nuovo, urgente progetto a cui stavo lavorando, e dovevo metterlo sul backburner. Al momento, sono bloccato tra le risposte di Cong e di Emilio. Probabilmente mi sposterò di più verso l'implementazione dei ctypes di Cong, ma mi piace ancora molto il metodo di analisi che usa 're'. Grazie per le grandi idee a tutti! –

risposta

12

Si consiglia di utilizzare le espressioni regolari (modulo re) per analizzare le informazioni desiderate dai file.

Costruire un parser C completo sarebbe enorme, ma se si utilizzano solo le variabili e il file è ragionevolmente semplice/prevedibile/sotto controllo, quindi ciò che è necessario scrivere è semplice.

Basta fare attenzione agli artefatti 'gotcha' come il codice commentato!

+3

Dai uno sguardo allo script [Tools/Scripts/h2py.py] (http://hg.python.org/cpython/log/70274d53c1dd/Tools/scripts/h2py.py), revisionato dal 1992. – eryksun

+0

Grazie Emilio e eryksun. Fino a quando ho visto la risposta di Cong, stavo credendo che questa fosse la strada da percorrere. Sarebbe un buon esercizio scrivere anche un parser per questo scopo. –

+0

@ManilaThrilla: sei il benvenuto.Ho letto e aggiornato la risposta di Cong, è molto istruttivo. Dal momento che è improbabile che una risposta migliore venga fuori dopo tutto questo tempo, ti suggerisco di contrassegnare Cong come accettato. –

1

Vorrei votare su emilio, ma mi manca un rappresentante!

Sebbene sia stato richiesto di evitare altre librerie non standard, è possibile dare un'occhiata a Cython (Cython: C-Extensions per Python www.cython.org/), che offre la flessibilità della codifica Python e della velocità raw di esecuzione di C/C++ - codice compilato.

In questo modo è possibile utilizzare regolarmente Python per tutto, ma gestire gli elementi costosi del codice utilizzando i suoi C-type integrati. È quindi possibile convertire il codice Python in file .c (o semplicemente racchiudere le librerie C esterne.), Che può quindi essere compilato in un file binario. Ho ottenuto fino a 10x speed-up facendo così per le routine numeriche. Credo anche che NumPy lo usi.

+0

Beh, ho originariamente implementato il mio codice in Cython, ma come ho affermato nella mia domanda, sto usando i ctypes ora per mantenere la portabilità. Il problema è che Cython non è disponibile nella libreria standard di Python, ma è ctypes. Ma hai ragione, Cython è fantastico e molto facile da usare. Però ho trovato che i ctype erano pochi microsecondi più veloci di cython. –

3

Si consiglia di utilizzare un tipo di file di configurazione leggibile sia dal programma Python che dal programma C, piuttosto che memorizzare valori costanti nelle intestazioni. Per esempio. un semplice csv, ini-file o anche il tuo semplice formato di coppie "chiave: valore".E non sarà necessario ricompilare il programma C ogni volta che si desidera modificare uno dei valori :)

+0

Sembra fantastico, ma penso che poi dovrei creare un parser per il programma C, che non voglio fare, o usare una libreria come LibConfig, che anch'io non voglio fare. Sarebbe bello, comunque, non dover ricompilare il programma C ogni volta. Hai un esempio per questo file di configurazione? –

+0

Una configurazione in formato JSON come esempio. Supportato dalla libreria standard di Python e molte implementazioni per C sono disponibili su http://www.json.org/ –

11

In generale, che definisce le variabili nel file di intestazione C è di stile scadente. Il file di intestazione deve solo dichiarare gli oggetti, lasciando la loro definizione per il file di codice sorgente ".c" appropriato.

Una cosa che si potrebbe voler fare è dichiarare le costanti globali della libreria come extern const whatever_type_t foo; e definirle (o "implementarle") (ad esempio assegnando loro valori) da qualche parte nel codice C (assicurarsi di farlo solo una volta).

In ogni caso, ignoriamo come lo fate. Supponiamo che tu abbia già definito le costanti e che i loro simboli siano visibili nel tuo file oggetto condiviso "libfoo.so". Supponiamo di voler accedere al simbolo pi, definito come extern const double pi = 3.1415926; in libfoo, dal tuo codice Python.

Ora è in genere caricare il file oggetto in Python utilizzando ctypes come questo:

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

Ma poi vedrete ctypes pensa libfoo.pi è una funzione, non un simbolo per i dati costanti!

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

Per accedere il suo valore, si deve fare qualcosa di imbarazzante - lanciando quello ctypes pensa è una funzione indietro in un numero.

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

In C gergo, questo corrisponde vagamente al seguente cosa che accade: Hai un const double pi, ma qualcuno ti costringe a usare solo tramite un puntatore a funzione:

typedef int (*view_anything_as_a_function_t)(void); 
view_anyting_as_a_function_t pi_view = &pi; 

Che cosa fate con il puntatore pi_view per utilizzare il valore di pi? Lo hai rinviato come const double * e disconnesso dallo stesso: *(const double *)(pi_view).

Quindi questo è tutto molto imbarazzante. Forse mi manca qualcosa ma questo credo sia dalla progettazione del modulo ctypes - è lì principalmente per effettuare chiamate con funzione esterna , non per accedere a dati "stranieri". Ed esportare il puro simbolo di dati in una libreria caricabile è probabilmente raro.

E questo non funzionerà se le costanti sono solo definizioni macro C. In generale, in nessun modo è possibile accedere esternamente ai dati definiti dalla macro. Sono espansi in fase di compilazione in macro, senza lasciare alcun simbolo visibile nel file di libreria generato, a meno che non sia esportare i loro valori di macro nel codice C.

+2

Bene, ho appena scoperto il modo non imbarazzante per farlo: http://python.net/crew/theller /ctypes/tutorial.html#accessing-values-exported-from-dlls Puoi provare 'pi = ctypes.c_double (libfoo," pi ")' in codice Python; questo restituisce un'istanza 'ctypes.c_double', e puoi accedere al suo valore con' pi.value'. –

+0

Grazie Cong per la tua risposta molto dettagliata. Penso che l'accesso ai valori delle istanze sia adatto al mio lavoro. È uno sforzo scientifico piuttosto che una vera e propria release del software, quindi vado per facilità e chiarezza. Sono curioso, però, su ciò che considereresti uno stile migliore per definire le costanti. Tieni presente che queste costanti devono trovarsi in un file separato in modo che sia semplice modificare o modificare rapidamente i loro valori. –

Problemi correlati