2011-11-22 7 views
15

Sto cercando un modo semplice per esporre un'istanza di classe C++ a un interprete incorporato in python.Esposizione di un'istanza di classe C++ a un interprete incorporato python

  • Ho una libreria C++. Questa libreria è avvolto (utilizzando sorso per il momento) e sono in grado di usarlo dall'interprete Python
  • Ho programma principale di C++, che instanciates una classe Foo dalla mia biblioteca e incorpora un interprete python

Vorrei esporre la mia istanza del mondo C++ di Foo al mondo python (e vista come una classe Foo).

È possibile, se sì, come?

penso che sia quasi come nella prima risposta di: boost::python::ptr or PyInstance_New usage

Credo che questo significa che devo usare boost.Python per avvolgere la mia libreria?

Il mio unico obiettivo è manipolare l'istanza di C++ di Foo nell'interprete python incorporato (non sono sicuro che sia possibile farlo con il metodo precedente).

Spero di essere chiaro, grazie per il vostro aiuto.

aggiornamento

Grazie per le vostre risposte. In effetti, ho già esposto la mia classe Foo a python (con swig).

Quello che ho:

mia classe Foo:

class Foo{...}; 

mia biblioteca avvolto (compresa la classe Foo) esposta a python: così posso iniziare l'interprete Python e fare qualcosa del genere:

import my_module 
foo=my_modulde.Foo() 

Cosa voglio:

Avere un programma principale C++ che incorpora un interprete python e manipola le variabili del mondo 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; 
} 

Più chiaro ora? :)

risposta

16

Boost python Consente di esporre le classi C++ in python in un modo molto strettamente integrato - è possibile anche racchiuderle in modo che sia possibile derivare classi python da quelle C++ e avere metodi virtuali risolti nelle sostituzioni python.

boost python tutorial è un buon punto di partenza.


edit:

È possibile creare un oggetto C++ e passare un riferimento ad esso per un interprete python interna in questo modo:

#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; 
} 
+0

Grazie per la risposta, I prenderà in considerazione anche boost.Python. Ero già a conoscenza della funzionalità boost.Python per esporre le classi C++ ma ho un sacco di codice legacy da includere. Quindi swig sembra una soluzione migliore per me (più veloce? Più semplice? E più target per le lingue) ... :( Ho trovato una delle tue vecchie risposte [qui] (http://stackoverflow.com/q/3378195/1044695). È ancora oscuro :) ma sento che è quello che sto cercando (non solo per un caso ma l'idea globale è qui)? Speravo di farlo con swig e python api? :( – jineff

+0

Ho aggiunto un esempio cercando di rispondere alla tua domanda esatta con boost :: python - ho paura di non poterti aiutare con lo swig – James

+0

Grazie mille! Questo è esattamente quello che voglio (tranne che è boost.python). ho menzionato la tua risposta come utile (molto utile in realtà :)). Aspetterò un po 'per altre risposte (specialmente riguardo a swig) e daremo un'occhiata più approfondita alla tua soluzione. – jineff

0

Secondo me è possibile creare un'interfaccia della classe ed esportare ti dal file dll (creare una libreria del progetto C++). Non so se sia possibile gestire com come interfacce in python, ma è comunque possibile esportare le funzioni di stile c per manipolare il comportamento della classe Foo.

0

Per riferimento, ecco come si può raggiungere questo utilizzando 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; 
}