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.

È stato utile?

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:

  1. Ho cambiato 'exec' in 'exec_file' da convenienza, funziona anche con semplicemente "exec".
  2. 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.
  3. 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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top