Ci sono due parti di questa risposta. Per prima cosa è necessario esporre la tua interfaccia in Python in un modo che permetta alle implementazioni di Python di sovrascrivere parti di esso a piacimento. Allora avete bisogno di mostrare il vostro programma C++ (in main
come chiamare Python
Esporre l'interfaccia esistente a Python:.
La prima parte è abbastanza facile da fare con SWIG ho modificato lo scenario esempio. un po 'per risolvere alcuni problemi e ha aggiunto una funzione aggiuntiva per il test:
// myif.h
class myif {
public:
virtual float myfunc(float a) = 0;
};
inline void runCode(myif *inst) {
std::cout << inst->myfunc(5) << std::endl;
}
per ora mi guardo il problema senza incorporare Python nell'applicazione, vale a dire che si avvia excetion in Python, non in int main()
in C++. È f facile da aggiungere semplicemente dopo.
Il primo è sempre cross-language polymorphism working:
%module(directors="1") module
// We need to include myif.h in the SWIG generated C++ file
%{
#include <iostream>
#include "myif.h"
%}
// Enable cross-language polymorphism in the SWIG wrapper.
// It's pretty slow so not enable by default
%feature("director") myif;
// Tell swig to wrap everything in myif.h
%include "myif.h"
Per fare che abbiamo attivato la funzione di direttore SWIG a livello globale e in particolare per la nostra interfaccia. Il resto è comunque piuttosto SWIG standard.
ho scritto un'implementazione di test di Python:
import module
class MyCl(module.myif):
def __init__(self):
module.myif.__init__(self)
def myfunc(self,a):
return a*2.0
cl = MyCl()
print cl.myfunc(100.0)
module.runCode(cl)
Con che ero poi in grado di compilare ed eseguire questo:
swig -python -c++ -Wall myif.i
g++ -Wall -Wextra -shared -o _module.so myif_wrap.cxx -I/usr/include/python2.7 -lpython2.7
python mycl.py
200.0
10
Esattamente quello che ci si speri di vedere da quel test.
Incorporare il Python nell'applicazione:
Next up abbiamo bisogno di implementare una versione reale del vostro mymain.cc. Ho messo insieme un abbozzo di quello che potrebbe essere simile:
#include <iostream>
#include "myif.h"
#include <Python.h>
int main()
{
Py_Initialize();
const double input = 5.0;
PyObject *main = PyImport_AddModule("__main__");
PyObject *dict = PyModule_GetDict(main);
PySys_SetPath(".");
PyObject *module = PyImport_Import(PyString_FromString("mycl"));
PyModule_AddObject(main, "mycl", module);
PyObject *instance = PyRun_String("mycl.MyCl()", Py_eval_input, dict, dict);
PyObject *result = PyObject_CallMethod(instance, "myfunc", (char *)"(O)" ,PyFloat_FromDouble(input));
PyObject *error = PyErr_Occurred();
if (error) {
std::cerr << "Error occured in PyRun_String" << std::endl;
PyErr_Print();
}
double ret = PyFloat_AsDouble(result);
std::cout << ret << std::endl;
Py_Finalize();
return 0;
}
E 'fondamentalmente solo standard di embedding Python in another application. Funziona e dà esattamente quello che ci si speri di vedere anche:
g++ -Wall -Wextra -I/usr/include/python2.7 main.cc -o main -lpython2.7
./main
200.0
10
10
L'ultimo pezzo del puzzle è quello di poter convertire la PyObject*
che si ottiene dal creare l'istanza in Python in un myif *
. SWIG lo rende ancora ragionevolmente semplice.
Per prima cosa dobbiamo chiedere a SWIG di esporre il suo runtime in un file di intestazione per noi. Lo facciamo con una chiamata in più a SWIG:
swig -Wall -c++ -python -external-runtime runtime.h
Poi abbiamo bisogno di ricompilare il nostro modulo di SWIG, dando esplicitamente la tabella dei tipi SWIG conosce un nome in modo che possiamo guardare in alto dall'interno della nostra principale. cc. Abbiamo ricompilare il .so utilizzando:
g++ -DSWIG_TYPE_TABLE=myif -Wall -Wextra -shared -o _module.so myif_wrap.cxx -I/usr/include/python2.7 -lpython2.7
Poi aggiungiamo una funzione di supporto per la conversione del PyObject*
al myif*
nel nostro main.cc:
#include "runtime.h"
// runtime.h was generated by SWIG for us with the second call we made
myif *python2interface(PyObject *obj) {
void *argp1 = 0;
swig_type_info * pTypeInfo = SWIG_TypeQuery("myif *");
const int res = SWIG_ConvertPtr(obj, &argp1,pTypeInfo, 0);
if (!SWIG_IsOK(res)) {
abort();
}
return reinterpret_cast<myif*>(argp1);
}
Ora questo è a posto si può usare dall'interno main()
:
int main()
{
Py_Initialize();
const double input = 5.5;
PySys_SetPath(".");
PyObject *module = PyImport_ImportModule("mycl");
PyObject *cls = PyObject_GetAttrString(module, "MyCl");
PyObject *instance = PyObject_CallFunctionObjArgs(cls, NULL);
myif *inst = python2interface(instance);
std::cout << inst->myfunc(input) << std::endl;
Py_XDECREF(instance);
Py_XDECREF(cls);
Py_Finalize();
return 0;
}
infine abbiamo compilare main.cc con -DSWIG_TYPE_TABLE=myif
e questo dà:
012.351.
./main
11
"Spero che questo sia sufficientemente chiaro" ... C + + avvolto in python e poi riavvolto in C++? – AJG85
Che cosa esattamente speri di realizzare costruendo questa infrastruttura? –
@ AJG85, non "incapsulato". Chiede di essere in grado di ereditare una classe C++ in Python e quindi di usarla in C++. (huh!) –