Python incorporato nel CPP:come ottenere i dati indietro al CPP
-
03-07-2019 - |
Domanda
Mentre si lavora su un progetto C++, ero alla ricerca di una libreria di terze parti per qualcosa che non è il mio core business.Ho trovato davvero una buona libreria, facendo esattamente ciò che è necessario, ma è scritto in Python.Ho deciso di sperimentare con l'incorporamento di codice Python in C++, utilizzando la Spinta.Libreria Python.
Il codice C++ sembra qualcosa di simile a questo:
#include <string>
#include <iostream>
#include <boost/python.hpp>
using namespace boost::python;
int main(int, char **)
{
Py_Initialize();
try
{
object module((handle<>(borrowed(PyImport_AddModule("__main__")))));
object name_space = module.attr("__dict__");
object ignored = exec("from myModule import MyFunc\n"
"MyFunc(\"some_arg\")\n",
name_space);
std::string res = extract<std::string>(name_space["result"]);
}
catch (error_already_set)
{
PyErr_Print();
}
Py_Finalize();
return 0;
}
Un (molto) semplificata versione di Python codice simile a questo:
import thirdparty
def MyFunc(some_arg):
result = thirdparty.go()
print result
Ora il problema è questo:'MyFunc' esegue bene, posso vedere la stampa di 'risultato'.Quello che non posso fare è leggere il 'risultato' di ritorno dal codice C++.L'estratto di comando non trova il 'risultato' in qualsiasi spazio dei nomi.Ho cercato la definizione di 'risultato' globale, ho anche provato la restituzione di una tupla, ma non riesco a farlo funzionare.
Soluzione
Prima di tutto, cambia la tua funzione in return
il valore. print
ing complicherà le cose poiché vuoi recuperare il valore. Supponiamo che il tuo MyModule.py
assomigli a questo:
import thirdparty
def MyFunc(some_arg):
result = thirdparty.go()
return result
Ora, per fare quello che vuoi, devi andare oltre l'incorporamento di base, come dice la documentazione . Ecco il codice completo per eseguire la tua funzione:
#include <Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pArg, *pResult;
int i;
Py_Initialize();
pName = PyString_FromString("MyModule.py");
/* Error checking of pName left out as exercise */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, "MyFunc");
/* pFunc is a new reference */
if (pFunc) {
pArgs = PyTuple_New(0);
pArg = PyString_FromString("some parameter")
/* pArg reference stolen here: */
PyTuple_SetItem(pArgs, 0, pArg);
pResult = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pResult != NULL) {
printf("Result of call: %s\n", PyString_AsString(pResult));
Py_DECREF(pResult);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function");
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load module");
return 1;
}
Py_Finalize();
return 0;
}
Altri suggerimenti
Basato su & # 932; & # 918; & # 937; & # 932; & # 918; & # 921; & # 927; & # 933 ;, Le risposte di Josh e Nosklo l'ho finalmente fatto funzionare usando boost.python:
Python:
import thirdparty
def MyFunc(some_arg):
result = thirdparty.go()
return result
C ++:
#include <string>
#include <iostream>
#include <boost/python.hpp>
using namespace boost::python;
int main(int, char **)
{
Py_Initialize();
try
{
object module = import("__main__");
object name_space = module.attr("__dict__");
exec_file("MyModule.py", name_space, name_space);
object MyFunc = name_space["MyFunc"];
object result = MyFunc("some_args");
// result is a dictionary
std::string val = extract<std::string>(result["val"]);
}
catch (error_already_set)
{
PyErr_Print();
}
Py_Finalize();
return 0;
}
Alcuni punti importanti:
- Ho cambiato 'exec' in 'exec_file' da convenienza, funziona anche con semplicemente "exec".
- Il motivo principale del fallimento è che i non ha superato un " local " name_sapce a "exec" o "exec_file" - questo è adesso risolto passando due volte name_space.
- Se la funzione python ritorna stringhe unicode, non lo sono convertibile in "std :: string", quindi i doveva suffissare tutte le stringhe di pitone con '.encode (' ASCII ',' ignore ')'.
Penso che ciò di cui hai bisogno sia PyObject_CallObject(<py function>, <args>)
, che restituisce il valore di ritorno della funzione chiamata come PyObject o PyRun_String(<expression>, Py_eval_input, <globals>, <locals>)
che valuta una singola espressione e restituisce il suo risultato.
Si dovrebbe essere in grado di restituire il risultato da MyFunc, che sarebbe poi finire nella variabile attualmente chiamata "ignorato".Questo elimina la necessità di accedere in qualsiasi altro modo.