python - swig cup
Pasando un objeto C++ a Python (2)
Esta es una respuesta parcial a mi propia pregunta. Lo digo parcial, porque creo que hay una mejor manera.
Sobre la base de esta publicación http://swig.10945.n7.nabble.com/Pass-a-Swig-wrapped-C-class-to-embedded-Python-code-td8812.html Generé el encabezado de tiempo de ejecución de swig, como se describe Aquí, la sección 15.4: http://www.swig.org/Doc2.0/Modules.html#Modules_external_run_time
Incluyendo el encabezado generado en el código C ++ anterior, permita que se escriba el siguiente código:
PyObject* pObj = SWIG_NewPointerObj((void*)&obj, SWIG_TypeQuery("_p_MyClass"), 0 );
Este código utiliza información de los archivos de origen de Swig python wrap, a saber, el nombre "swig" del tipo MyClass, es decir, _p_MyClass .
Con el PyObject * anterior como un argumento a la función PyObject_CallObject, la función execute () de python en el código anterior se ejecuta correctamente, y el código de Python, que utiliza el módulo python generado, tiene acceso adecuado a los datos internos de los objetos MyClass. Esto es genial.
Aunque el código anterior ilustra cómo pasar y recuperar datos entre C ++ y Python de una manera bastante simple, no es lo ideal, en mi opinión.
El uso del archivo de encabezado de swig en el código de C ++ no es realmente tan bonito, y además, requiere que el usuario examine "manualmente" el código de envoltorio generado por swig para encontrar el código "_p_MyClass".
¿¡Debe haber una mejor manera!? ¿Tal vez debería agregarse algo al archivo de interfaz swig para que esto se vea mejor?
Esta pregunta trata sobre cómo pasar un objeto C ++ a una función de Python que se llama en un intérprete de Python integrado (C ++) .
La siguiente clase de C ++ (MyClass.h) está diseñada para pruebas:
#ifndef MyClassH
#define MyClassH
#include <string>
using std::string;
class MyClass
{
public:
MyClass(const string& lbl): label(lbl) {}
~MyClass(){}
string getLabel() {return label;}
private:
string label;
};
#endif
Un módulo de Python, que expone la clase C ++, puede ser generado por el siguiente archivo de interfaz Swig:
%module passmetopython
%{ #include "MyClass.h" %}
%include "std_string.i"
//Expose to Python
%include "MyClass.h"
A continuación se muestra una secuencia de comandos de Python que utiliza el módulo de Python
import passmetopython as pmtp
def execute(obj):
#This function is to be called from C/C++, with a
#MyClass object as an argument
print ("Entering execute function")
lbl = obj.getLabel();
print ("Printing from within python execute function. Object label is: " + lbl)
return True
def main():
c = pmtp.MyClass("Test 1")
retValue = execute(c)
print("Return value: " + str(retValue))
#Test function from within python
if __name__ == ''__main__'':
main()
Esta pregunta es sobre cómo hacer que funcione la función python execute () , cuando se llama desde c ++, con un objeto C ++ como argumento.
El siguiente programa de C ++ se escribió para probar las funciones (cantidad mínima de comprobación de errores):
#include "Python.h"
#include <iostream>
#include <sstream>
#include "MyClass.h"
using namespace std;
int main()
{
MyClass obj("In C++");
cout << "Object label: /"" << obj.getLabel() << "/"" << endl;
//Setup the Python interpreter and eventually call the execute function in the
//demo python script
Py_Initialize();
//Load python Demo script, "passmetopythonDemo.py"
string PyModule("passmetopythonDemo");
PyObject* pm = PyUnicode_DecodeFSDefault(PyModule.c_str());
PyRun_SimpleString("import sys");
stringstream cmd;
cmd << "sys.path.append(/"" << "." << "/")";
PyRun_SimpleString(cmd.str().c_str());
PyObject* PyModuleP = PyImport_Import(pm);
Py_DECREF(pm);
//Now create PyObjects for the Python functions that we want to call
PyObject* pFunc = PyObject_GetAttrString(PyModuleP, "execute");
if(pFunc)
{
//Setup argument
PyObject* pArgs = PyTuple_New(1);
//Construct a PyObject* from long
PyObject* pObj(NULL);
/* My current attempt to create avalid argument to Python */
pObj = PyLong_FromLong((long) &obj);
PyTuple_SetItem(pArgs, 0, pObj);
/***** Calling python here *****/
cout<<endl<<"Calling function with an MyClass argument/n/n";
PyObject* res = PyObject_CallObject(pFunc, pArgs);
if(!res)
{
cerr << "Failed calling function..";
}
}
return 0;
}
Cuando se ejecuta el código anterior, la función de python execute () , con un objeto MyClass como argumento, falla y devuelve NULL. Sin embargo, la función Python se ingresa, ya que puedo ver la salida ( Entrando en la función de ejecución ) en la salida de la consola, lo que indica que el objeto que se aprobó no es, de hecho , un objeto MyClass válido.
Hay muchos ejemplos sobre cómo pasar tipos simples, como ints, dobles o tipos de cadenas a Python desde C / C ++. Pero hay muy pocos ejemplos que muestran cómo pasar un objeto / puntero C / C ++, lo cual es un tanto desconcertante.
El código anterior, con un archivo CMake, se puede consultar en github: https://github.com/TotteKarlsson/miniprojects/tree/master/passMeToPython
Este código no debe usar ningún impulso de python u otra API. Sin embargo, Cython parece interesante, y si se puede usar para simplificar en el lado de C ++, podría ser aceptable.
PyObject *pValue;
pValue = PyObject_CallMethod(pInstance, "add","(i)",x);
if (pValue)
Py_DECREF(pValue);
else
PyErr_Print();