2011-11-22 14 views
15

Poszukuję prostego sposobu na ujawnienie instancji klasy C++ dla wbudowanego interpretera Pythona.Wystawianie instancji klasy C++ do interpretera osadzonego w pythonie

  • Mam bibliotekę C++. Ta biblioteka jest owinięta (używając łyk za chwilę) i jestem w stanie go używać z interpretera Pythona
  • Mam C++ program główny, który instanciates klasę Foo z mojej biblioteki i osadza interpreter Pythona

Chciałbym odsłonić moją instancję światową C++ Foo do świata Pythona (i postrzeganą jako klasa Foo).

Czy to możliwe, jeśli tak, w jaki sposób?

Myślę, że to prawie jak w pierwszej odpowiedzi na: boost::python::ptr or PyInstance_New usage

Myślę, że to oznacza, że ​​należy używać boost.Python zawinąć moją bibliotekę?

Moim jedynym celem jest manipulowanie moją instancją C++ Foo we wbudowanym interpreterze python (nie jestem pewien, czy można to zrobić za pomocą poprzedniej metody).

Mam nadzieję, że jestem jasny, dziękuję za pomoc.

aktualizacja

Dzięki za odpowiedzi. W rzeczywistości, już wystawiłem moją klasę Foo na pythona (z swigiem).

Co mam:

moja klasa Foo:

class Foo{...}; 

mój zawinięte biblioteki (w tym klasy Foo) narażone na pytona: więc mogę uruchomić interpreter Pythona i zrób coś takiego:

import my_module 
foo=my_modulde.Foo() 

Co chcę:

Posiadanie programu głównego C++, który osadza interpretera python i manipuluje zmiennymi światowymi 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; 
} 

Czy to jasne? :)

Odpowiedz

16

Boost python Pozwala wystawiać C++ klas do pytona w bardzo ściśle zintegrowany sposób - można nawet owinąć je tak, że można czerpać klas Pythona od C++ nich, i metod wirtualnych rozwiązane do nadpisania Pythonie.

boost python tutorial to dobre miejsce na rozpoczęcie.


edit:

Można tworzyć C++ przedmiotu i przekazać referencję do niej z wewnętrznym interpretera Pythona jak ten:

#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

Dzięki za odpowiedź, I rozważy również boost.Python. Byłem już świadomy możliwości boost.Python do ujawnienia klas C++, ale mam dużo starszego kodu do zawijania. Więc to wygląda na lepsze rozwiązanie (szybciej, bardziej proste i więcej celów językowych) ... :( Znalazłem jedną ze starych odpowiedzi [tutaj] (http://stackoverflow.com/q/3378195/1044695) .To wciąż jest niejasne :) ale czuję, że tego właśnie szukam (nie tylko dla jednej instancji, ale idea globalna jest tutaj)? Miałem nadzieję, że to zrobię z apką świst i pytona? :( – jineff

+0

Dodałem przykład próbujący odpowiedzieć na twoje dokładne pytanie z boost :: python - boję się, że nie mogę pomóc z łykiem – James

+0

Wielkie dzięki! Dokładnie to, czego chcę (z wyjątkiem boost.python). wspomniałem twoją odpowiedź jako użyteczną (bardzo przydatna). Poczekaj chwilę na inne odpowiedzi (szczególnie dotyczące łykania) i przyjrzyj się dokładniej Twojemu rozwiązaniu. – jineff

0

Moim zdaniem można utworzyć interfejs klasy i wyeksportować plik ti z pliku dll (utworzyć bibliotekę projektu C++). Nie wiem, czy można zarządzać com jak interfejsy w python, ale nadal można eksportować funkcje stylu c w celu manipulowania zachowanie swojej klasy Foo.

0

Dla porównania, oto jak można osiągnąć to przy użyciu 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; 
} 
Powiązane problemy