Scusami per il ritardo con cui rispondo.
Ho fatto un po' di esperimenti. Sotto riporto il codice di alcuni
esperimenti di chiamate complesse, che vanno dal codice minimale fino a
quello che considera i casi di errore.
Ho confrontato questo codice con quello del PyRun_SimpleString, e a
dire il vero mentre il codice piu' complesso si espone a molti crash,
quello con il PyRun_SimpleString mi riporta normalmente l'errore nello
script senza crash e con segnalazioni precise.
Quindi secondo me questo: "there is no way to get the exception
information": probabilmente si riferisce al fatto che con pyRun non c'e'
modo di intercettare il messaggio di errore per passarlo al programma in
C, ma non al fatto che l'errore non venga correttamente segnalato
all'utente python.
Ecco l'esempio di inclusione complessa *senza controlli*. Un errore
qualsiasi sui puntatori causa il crash dell'interprete.
--------------------------------------------
/*Esempio minimale, senza controlli, per eseguire una funzione python
python chiamandola dal C, con due argomenti*/
#include<stdio.h>
#include<stdlib.h>
#include <Python.h>
int main()
{
Py_Initialize();
int valDaPassare1 = 10;
float valDaPassare2 = 5.0;
char *valoreDiRitorno;
PyObject *mioModulo = PyImport_ImportModule( "myfunctions" );
PyObject *funzioneDelMioModulo = PyObject_GetAttrString( mioModulo, "foo" );
PyObject *risultato = PyObject_CallFunction(funzioneDelMioModulo,
"(i,f)", valDaPassare1,valDaPassare2);
PyArg_Parse( risultato, "s", &valoreDiRitorno );
printf("%s\n",valoreDiRitorno);
Py_DECREF( mioModulo );
Py_DECREF( funzioneDelMioModulo );
Py_DECREF( risultato );
Py_Finalize();
return 1;
}
/*ovviamente deve esserci anche un file chiamato
myfunctions.py che contiene la funfione "foo". Io
ho usata questa:
def foo(n,i):
print "fooo"+str(n)
return str(n)+str(i)
Se non trova il modulo crasha...Poiche' facciamo anche il
parsing del valore di ritorno, se la funzione python non ritorna
qualcosa crasha...
*/
--------------------------------------------
La versione con i controlli necessari e' mooolto piu' complessa:
--------------------------------------------
#include<stdio.h>
#include<stdlib.h>
#include <Python.h>
int main()
{
Py_Initialize();
int valDaPassare1 = 10;
float valDaPassare2 = 5.0;
char *valoreDiRitorno;
PyObject *mioModulo = PyImport_ImportModule( "myfunctions" );
if (mioModulo != NULL)
{
PyObject *funzioneDelMioModulo = PyObject_GetAttrString(
mioModulo, "foo" );
if (funzioneDelMioModulo != NULL &&
PyCallable_Check(funzioneDelMioModulo))
{
PyObject *risultato =
PyObject_CallFunction(funzioneDelMioModulo, "(i,f)",
valDaPassare1,valDaPassare2);
if (risultato != NULL)
{
//Se c'e' il risultato lo copiamo dentro valoreDiritorno
//stampiamo, e poi cancelliamo il puntatore al risultato
PyArg_Parse( risultato, "s", &valoreDiRitorno );
printf("%s\n",valoreDiRitorno);
Py_DECREF( risultato );//Ormai non ci serve piu'
}
else
{
//Se il risultato e' NULL cancelliamo i puntatori fatti
//stampiamo un errore e ritorniamo un valore
Py_DECREF( mioModulo );
Py_DECREF( funzioneDelMioModulo );
fprintf(stderr,"La funzione foo ha restituito NULL\n");
return 1;
}
}
else
{
//Se la funzione non esiste oppure non e' un oggetto evocabile
if (PyErr_Occurred())
PyErr_Print();
}
//Ora i puntatori non ci servono piu' e li dobbiamo cancellare
//XDECREF perche' qui non sappiamo se il valore e di
funzioneDelMioModulo e' NULL
Py_XDECREF( funzioneDelMioModulo );
//Poiche' siamo nell'if (mioModulo != NULL) sappiamo che non è
NULL e possiamo
//usare DECREF
Py_DECREF( mioModulo );
}
else
{
//Se il modulo non viene trovato
if (PyErr_Occurred())
PyErr_Print();
}
Py_Finalize();
return 1;
}
------------------------------------------
Ma alla fine le differenza secondo me sono solo 2:
1) Con la forma complessa si possono passare argomenti elaborati in C,
direttamente alle funzion python.
2) Con la forma complessa si può gestire l'errore in qualche modo, se si
ha bisogno di qualcosa in piu' del semplice traceback.
Che ne pensi?
ciao,
Manuel
Post by Lawrence OluyedePost by ManuelOvviamente nel C++ chiamate a PyRun_SimpleString(s) avvengono sempre
dopo che e' stato parsato il file python che definisce la funzione pippo.
Sto usando questo metodo come alternativa al ben piu' complesso
http://docs.python.org/ext/callingPython.html
che mi costringerebbe a fare molto, molto lavoro.
In generale che ve ne pare?
Mi pare una scorciatoia rischiosa, una sorta di eval da usare solo spot.
Se sei confident che il codice Python non possa dare eccezioni.
La documentazione <http://docs.python.org/api/veryhigh.html#l2h-53>
"""
int PyRun_SimpleString(
const char *command)
This is a simplified interface to PyRun_SimpleStringFlags() below,
leaving the PyCompilerFlags* argument set to NULL.
int PyRun_SimpleStringFlags(
const char *command, PyCompilerFlags *flags)
Executes the Python source code from command in the __main__ module
according to the flags argument. If __main__ does not already exist, it
is created. Returns 0 on success or -1 if an exception was raised. If
there was an error, there is no way to get the exception information.
For the meaning of flags, see below.
"""