|
|
(Basata sulla FAQ aggiornata al 28 Giugno 1999)
Per ulteriori informazioni, si consultino i libri specifici su Python, come Programming Python o Internet Programming with Python.
extern "C" { ... }
i file include di Python e anteporre extern "C"
ad ogni funzione che dovrà essere chiamata dall'interprete Python. L'uso di oggetti globali o "static" del C++ con costruttori non può proprio definirsi una buona idea.
Esiste anche una API di alto livello per gli oggetti Python, che viene fornita dalla cosiddetta "interfaccia astratta" – leggi Include/abstract.h per ulteriori informazioni. Questo permette ad esempio di interfacciarsi con qualunque tipo di sequenza Python (ad esempio liste o tuple) usando chiamate come PySequence_Length(), PySequence_GetItem(), ecc. come pure con molti altri utili protocolli.
object *call_method(object *inst, char *methodname, char *format, ...) { object *method; object *args; object *result; va_list va; method = getattr(inst, methodname); if (method == NULL) return NULL; va_start(va, format); args = vmkvalue(format, va); va_end(va); if (args == NULL) { DECREF(method); return NULL; } result = call_object(method, args); DECREF(method); DECREF(args); return result; }Questo funziona per qualsiasi istanza che ha un metodo – built-in o definito dall'utente. Sarà tua responsabilità effettuare un eventuale DECREF del valore restituito.
Per chiamare ad esempio un metodo "seek" di un oggetto file con argomento 10,0 (assumendo che il puntatore all'oggetto file sia "f"):
res = call_method(f, "seek", "(OO)", 10, 0); if (res == NULL) { ... è sopraggiunta un'eccezione ... } else { DECREF(res); }Nota che, dal momento che call_object() richiede sempre una tuple come argomento, per chiamare una funzione senza argomenti il formato da passare è "()" e che per chiamare una funzione con un solo argomento questo va racchiuso tra parentesi, p.e. "(i)".
Nel codice Python, definisci un oggetto che supporti il metodo "write()". Fai un "redirect" di sys.stdout e sys.stderr a questo oggetto. Chiama print_error, o fai sempicemente girare il normale meccanismo di "traceback". Quindi, l'output finirà dovunque il tuo metodo write() vorrà mandarlo.
La via più semplice per farlo è usare la classe StringIO della libreria standard.
Ecco una semplice porzione di codice che cattura stdout:
>>> class StdoutCatcher: ... def __init__(self): ... self.data = '' ... def write(self, stuff): ... self.data = self.data + stuff ... >>> import sys >>> sys.stdout = StdoutCatcher() >>> print 'foo' >>> print 'hello world!' >>> sys.stderr.write(sys.stdout.data) foo hello world!
module = PyImport_ImportModule("<modulename>");Se il modulo non è ancora stato importato, (cioè se non è ancora presente in sys.modules), questo inizializza il modulo; d'altra parte questo restituisce semplicemente il valore di sys.modules["<modulename>"]. Nota che questo non inserisce il nome del modulo in nessun namespace -- questo assicura soltanto che è stato inizializzato ed è conservato in sys.modules .
Quindi puoi accedere agli attributi del modulo (cioè ai nomi definiti nel modulo) come segue:
attr = PyObject_GetAttrString(module, "<attrname>");Lo stesso risultato può essere ottenuto chiamando PyObject_SetAttrString(), per effettuare assegnamenti alle variabili nel modulo.
Un interessante approccio automatizzato (che funziona anche per il C) è SWIG, reperibile presso www.swig.org.
Rimuovi le linee:
#include "allobjects.h" #include "modsupport.h"Ed inserisci invece:
#include "Python.h"Puoi anche avere bisogno di aggiungere:
#include "rename2.h"Se il modulo utilizza "nomi vecchi".
Questo può succedere anche con altri vecchi moduli di Python, e si applica lo stesso rimedio.
Ogni funzione init di un modulo deve avere una linea simile a:
module = Py_InitModule("yourmodule", yourmodule_functions);Se la stringa passata a questa funzione non è lo stesso nome del tuo modulo di estensione, sorgerà il SystemError in questione.