Home Documentazione in italiano Aiuto Link FAQ

La FAQ di Python - Sezione 5

(Basata sulla FAQ aggiornata al 28 Giugno 1999)


5. Estendere Python


5.1. Posso scrivere le mie funzioni in C?

Sì, puoi scrivere in C moduli built-in contenenti funzioni, variabili, eccezioni e persino nuovi tipi. Tutto questo è spiegato nel documento "Extending and Embedding the Python Interpreter" (il file LaTeX Doc/ext.tex). Leggi anche il capitolo relativo al caricamento dinamico ("dynamic loading").

Per ulteriori informazioni, si consultino i libri specifici su Python, come Programming Python o Internet Programming with Python.


5.2. Posso scrivere le mie funzioni in C++?

Sì, usando le caratteristiche di compatibilità del C++ col C. In sostanza devi racchiudere in 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.


5.3. Come posso eseguire istruzioni Python a piacere da C?

La funzione a più alto livello per fare questo è PyRun_SimpleString(), che prende come argomento una singola stringa, che viene eseguita nel contesto del modulo __main__, e restituisce 0 in caso di successo, oppure –1 se insorge una eccezione (anche del tipo Syntax Error). Per avere più potere di controllo, usa PyRun_String(); vedi il sorgente di PyRun_SimpleString() in Python/pythonrun.c.


5.4. Come posso valutare un'espressione Python a piacere da C?

Chiama la funzione PyRun_String() del punto precedente con il simbolo eval_input (Py_eval_input si trova a partire dalla versione 1.5a1); questo prende una espressione, la valuta e ne restituisce il valore.


5.5. Come posso estrarre dei valori per C da un oggetto Python?

Questo dipende dal tipo dell'oggetto. Se si tratta di una tuple, PyTupleSize(o) restituisce la sua lunghezza e PyTuple_GetItem(o, i) restituisce l'i-esimo elemento; lo stesso avviene per le liste con PyListSize(o) e PyList_GetItem(o, i). Per le stringhe, PyString_Size(o) restituisce la lunghezza e PyString_AsString(o) un puntatore al suo valore (nota che le stringhe in Python possono contenere byte null, perciò strlen() non è sicuro). Per controllare a quale tipo un oggetto appartenga, prima assicurati che non sia un NULL, e poi usa PyString_Check(o), PyTuple_Check(o), PyList_Check(o), ecc.

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.


5.6. Come faccio ad usare Py_BuildValue() per creare una tuple di dimensione arbitraria?

Non puoi. Invece, usa t = PyTuple_New(n), e riempila con oggetti usando PyTuple_SetItem(t, i, o) – nota che questo consuma un `reference count' di o. La stessa cosa si può fare con le liste, con PyList_New(n) e PyList_SetItem(l, i, o). Nota che tu devi impostare tutti gli elementi della tuple ad un qualche valore prima di poter passare la tuple al codice Python -- PyTuple_New(n) li inizializza a NULL, che non è un valore valido per Python.


5.7. Come faccio a chiamare il metodo di un oggetto da C?

Ecco una funzione (non testata), che potrebbe diventare parte della prossima release in qualche forma, che usa <stdarg.h> per permettere il passaggio di una lista di argomenti a vmkvalue():

        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)".


5.8. Come faccio a catturare l'output di PyErr_Print() (o di qualunque cosa che stampi su stdout/stderr)?

(Grazie a Mark Hammond):

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!


5.9.Come faccio ad accedere ad un modulo scritto in Python da C?

Puoi ottenere un puntatore all'oggetto modulo come segue:

        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.

5.10. Come posso interfacciare gli oggetti C++ da Python?

Questo dipende da ciò di cui hai bisogno: ci sono diverse strade. Per farlo manualmente, comincia a leggere il documento "Extending and Embedding" (Doc/ext.tex, vedi anche http://www.python.org/doc). Renditi conto che per il sistema runtime di Python, non c'è molta differenza tra C e C++ -- così la tecnica di costruire un nuovo tipo in Python attorno ad una struttura C (puntatore), funzionerà anche per gli oggetti C++.

Un interessante approccio automatizzato (che funziona anche per il C) è SWIG, reperibile presso www.swig.org.


5.11. Non riesco a fare il building di mSQLmodule (o qualche altro vecchio modulo) con Python 1.5 (o successivo)

Da python-1.4, "Python.h" ha tutti i file include necessari in un modulo di estensione. La retrocompatibilità è stata abbandonata dopo la versione 1.4 e per questo non può essere effettuato il building con mSQLmodule.c poiché "allobjects.h" non può essere trovato. La seguente modifica a mSQLmodule.c è innocua quando viene fatto il building con la versione 1.4 e necessaria per effettuarlo con le versioni Python successive:

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.


5.12. Ho aggiunto un modulo usando il file Setup e il make non è andato a buon fine! Che succede?

Setup deve terminare con un carattere di interruzione di riga (`newline'), se questo manca nascono i problemi. A parte questa possibilità, forse puoi avere altri problemi di linking che non sono specifici di Python.


5.13. Voglio compilare un modulo sul mio sistema Linux Red Hat, ma mancano alcuni file.

Gli RPM RedHat di Python non contengono la directory /usr/lib/python1.x/config/, che comprende diversi file richiesti per la compilazione delle estensioni Python. Installa gli RPM di python-devel per disporre dei file necessari.


5.14. Cosa significa "SystemError: _PyImport_FixupExtension: module yourmodule not loaded"?

Questo significa che tu hai creato un modulo di estensione chiamato "yourmodule", ma la funzione init del tuo modulo non effettua l'inizializzazione con tale nome.

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.


Potete inviare commenti e correzioni a questo doc a python.it@tiscalinet.it.