c++ python boost swig boost-python

Exponer una instancia de clase de C++ a un intérprete incorporado de python



boost swig (3)

Estoy buscando una forma sencilla de exponer una instancia de clase de C ++ a un intérprete incorporado de python.

  • Tengo una biblioteca de C ++. Esta biblioteca está envuelta (usando un trago por el momento) y puedo usarla desde el intérprete de python
  • Tengo un programa principal de C ++ que crea una clase de Foo desde mi biblioteca e integra un intérprete de Python

Me gustaría exponer mi instancia mundial de C ++ de Foo al mundo de los pitones (y visto como una clase de Foo).

¿Es esto posible, si es así, cómo?

Creo que es casi como en la primera respuesta de: boost :: python :: ptr o PyInstance_New use

Supongo que esto significa que debería usar boost.Python para envolver mi biblioteca?

Mi único objetivo es manipular mi instancia en C ++ de Foo en el intérprete de Python incrustado (no estoy seguro de que pueda hacerse con el método anterior).

Espero que quede claro, gracias por tu ayuda.

actualizar

Gracias por tus respuestas. De hecho, ya he expuesto mi clase de Foo a python (con swig).

Lo que tengo:

mi clase de foo

class Foo{...};

mi biblioteca envuelta (incluida la clase Foo) expuesta a python: así puedo iniciar el intérprete de python y hacer algo como esto:

import my_module foo=my_modulde.Foo()

Lo que quiero:

Tener un programa principal de C ++ que incrusta un intérprete de Python y manipula las variables del mundo de C ++.

int main(int argc, char **argv) { Foo foo; // instanciates foo Py_Initialize(); Py_Main(argc, argv); // starts the python interpreter // and manipulates THE foo instance in it Py_Finalize(); return 0; }

Más claro ahora? :)


Para referencia, aquí es cómo puede lograr esto usando pybind11 :

#include <pybind11/pybind11.h> #include <iostream> namespace py = pybind11; class Foo { public: Foo(const std::string &s) : s_(s) {} void doSomething() { std::cout << s_ << std::endl; } private: std::string s_; }; typedef std::shared_ptr<Foo> FooPtr; PYBIND11_PLUGIN(FooModule) { py::module m("FooModule"); py::class_<Foo, FooPtr>(m, "Foo") .def("doSomething", &Foo::doSomething); return m.ptr(); } int main(int argc, char **argv) { // Create Foo instance in C++ FooPtr foo = std::make_shared<Foo>("Hello, World!"); // Initialize interpreter and import module defining Foo wrapper PyImport_AppendInittab("FooModule", PyInit_FooModule); Py_Initialize(); PyRun_SimpleString("import FooModule"); // Make Foo instance accessible in python py::module main = py::module::import("__main__"); main.attr("foo") = foo; // Test that it works PyRun_SimpleString("foo.doSomething()"); // Finalize Py_Finalize(); return 0; }


Sé que esta es una pregunta antigua, pero aquí hay una solución que usa SWIG.

foo.h:

#pragma once #include <string> struct Foo{ Foo(); Foo(std::string const& s); void doSomething(); std::string m_string; };

foo.cpp:

#include "foo.h" #include <iostream> Foo::Foo() {} Foo::Foo(std::string const& s) : m_string(s) {} void Foo::doSomething() { std::cout << "Foo:" << m_string << std::endl; }

foo.i:

%module module %{ #include "foo.h" %} %include "std_string.i" %include "foo.h"

Generar el contenedor SWIG habitual junto con un tiempo de ejecución

swig -python -c++ -Wall foo.i swig -python -c++ -Wall -external-runtime runtime.h

Genera el módulo SWIG que contiene la struct Foo :

g++ -fPIC -Wall -Wextra -shared -o _module.so foo_wrap.cxx foo.cpp -I/usr/include/python2.7 -lpython2.7

Si desea compartir información de tipo en varios módulos, se puede agregar un argumento -DSWIG_TYPE_TABLE=SomeName .

Ahora, aquí está cómo una instancia de C ++ de Foo se pasa al intérprete

#include "foo.h" #include <Python.h> #include "runtime.h" int main(int argc, char **argv) { Py_Initialize(); PyObject* syspath = PySys_GetObject((char*)"path"); PyObject* pName = PyString_FromString((char*) "."); int err = PyList_Insert(syspath, 0, pName); Py_DECREF(pName); err = PySys_SetObject((char*) "path", syspath); PyObject *main, *module, *pInstance, *run, *setup; try { main = PyImport_ImportModule("__main__"); err = PyRun_SimpleString( "a_foo = None/n" "/n" "def setup(a_foo_from_cxx):/n" " print ''setup called with'', a_foo_from_cxx/n" " global a_foo/n" " a_foo = a_foo_from_cxx/n" "/n" "def run():/n" " a_foo.doSomething()/n" "/n" "print ''main module loaded''/n"); // Load Python module module = PyImport_ImportModule("module"); swig_type_info *pTypeInfo = nullptr; pTypeInfo = SWIG_TypeQuery("Foo *"); Foo* pFoo = new Foo("Hello"); int owned = 1; pInstance = SWIG_NewPointerObj(reinterpret_cast<void*>(pFoo), pTypeInfo, owned); setup = PyObject_GetAttrString(main, "setup"); PyObject* result = PyObject_CallFunctionObjArgs(setup, pInstance, NULL); Py_DECREF(result); run = PyObject_GetAttrString(main, "run"); result = PyObject_CallFunctionObjArgs(run, NULL); Py_DECREF(result); } catch (...) { PyErr_Print(); } Py_DECREF(run); Py_DECREF(setup); Py_DECREF(pInstance); Py_DECREF(module); Py_DECREF(main); Py_Finalize(); return 0; }

Lo anterior puede ser compilado por:

g++ -Wall -Wextra -I/usr/include/python2.7 main.cpp foo.cpp -o main -lpython2.7


Boost python Le permite exponer las clases de c ++ a python de una manera muy integrada, incluso puede envolverlas para que pueda derivar clases de python de sus clases de c ++, y tener métodos virtuales resueltos para las modificaciones de python.

El tutorial de boost python es un buen lugar para comenzar.

editar:

Puede crear un objeto c ++ y pasarle una referencia a un intérprete de python interno como este:

#include <boost/shared_ptr.hpp> #include <boost/make_shared.hpp> #include <boost/python.hpp> #include <string> #include <iostream> namespace bp = boost::python; struct Foo{ Foo(){} Foo(std::string const& s) : m_string(s){} void doSomething() { std::cout << "Foo:" << m_string << std::endl; } std::string m_string; }; typedef boost::shared_ptr<Foo> foo_ptr; BOOST_PYTHON_MODULE(hello) { bp::class_<Foo, foo_ptr>("Foo") .def("doSomething", &Foo::doSomething) ; }; int main(int argc, char **argv) { Py_Initialize(); try { PyRun_SimpleString( "a_foo = None/n" "/n" "def setup(a_foo_from_cxx):/n" " print ''setup called with'', a_foo_from_cxx/n" " global a_foo/n" " a_foo = a_foo_from_cxx/n" "/n" "def run():/n" " a_foo.doSomething()/n" "/n" "print ''main module loaded''/n" ); foo_ptr a_cxx_foo = boost::make_shared<Foo>("c++"); inithello(); bp::object main = bp::object(bp::handle<>(bp::borrowed( PyImport_AddModule("__main__") ))); // pass the reference to a_cxx_foo into python: bp::object setup_func = main.attr("setup"); setup_func(a_cxx_foo); // now run the python ''main'' function bp::object run_func = main.attr("run"); run_func(); } catch (bp::error_already_set) { PyErr_Print(); } Py_Finalize(); return 0; }