2013-08-26 10 views
5

Chcę wiedzieć, czy jest jakikolwiek sposób, aby wystawić klasę C++ do Pythona, ale bez budowania pośredniej biblioteki współdzielonej.Jak odsłonić klasę C++ do Pythona bez budowania modułu

Oto mój pożądany scenariusz. Na przykład mam następujące C++ klasa:

class toto 
    { 
    public: 
     toto(int iValue1_, int iValue2_): iValue1(iValue1_), iValue2(iValue2_) {} 
     int Addition(void) const {if (!this) return 0; return iValue1 + iValue2;} 

     private: 
     int iValue1; 
     int iValue2; 
    }; 

Chciałbym przekonwertować jakoś tę klasę (lub jego intance) do PyObject * w celu wysłania go jako paremter (args), aby na przykład PyObject_CallObject:

PyObject* PyObject_CallObject(PyObject* wrapperFunction, PyObject* args) 

w drugiej strony w moim boku Pythona, będę mieć wrapperFunction która pobiera wskaźnik na moim C++ klasy (lub jej instancji) jako parametr i wywołuje jego metody lub wykorzystuje swoje właściwości:

def wrapper_function(cPlusPlusClass): 
    instance = cPlusPlusClass(4, 5) 
    result = instance.Addition() 

Jak widać, tak naprawdę nie potrzebuję/chcę mieć oddzielnej biblioteki współdzielonej lub budować modułu przez pythona doładowania. Wszystko, czego potrzebuję, to znaleźć sposób na przekonwertowanie kodu C++ do PyObject i wysłanie go do Pythona. Nie mogę znaleźć sposobu, aby to zrobić przez biblioteki C python, boost lub SWIG.

Czy masz jakiś pomysł? Dzięki za pomoc.

+1

nie jestem pewien, czy rozumiem dokładnie, co chcesz. Boost.Python ma 'boost :: python :: object :: ptr', które zwraca' PyObject * '- czy tego właśnie szukałeś? –

+1

Wierzę, że możliwy jest dostęp do C/C++ za pomocą 'ctypes', ale może to być trudne zadanie, aby odsłonić klasę C++. – Bakuriu

+0

@PaulManta: Dzięki za odpowiedź. To, czego chcę, składa się z 3 kroków: Krok 1: obuduj klasę C++ w obiekcie PyObject.Step2 wyślij ten wskaźnik do funkcji Pythona. Krok 3. przy użyciu tego wskaźnika C++ w Pythonie (tj. wywoływanie jego metod). Czy mógłbyś być bardziej pragmatyczny i powiedzieć, jak można zaimplementować kod C++ do obiektu :: ptr? –

Odpowiedz

1

Znalazłem odpowiedź. Właściwie czego szukałem było całkiem podobna do tej odpowiedzi (dzięki moooeeeep jego komentarzu):

Exposing a C++ class instance to a python embedded interpreter

obserwuję C++ klasa (! Uwaga konstruktor domyślny jest obowiązkowe):

class TwoValues 
{ 
public: 
    TwoValues(void): iValue1(0), iValue2(0) {} 
    TwoValues(int iValue1, int iValue2): iValue1(iValue1_), iValue2(iValue2_) {} 

    int Addition(void) const {if (!this) return 0; return iValue1 + iValue2;} 

public: 
    int iValue1; 
    int iValue2; 
}; 

mógłby być narażony przez impuls wykonując makro:

BOOST_PYTHON_MODULE(ModuleTestBoost) 
{ 
class_<TwoValues>("TwoValues") 
    .def("Addition",    &TWOVALUES::Addition) 
    .add_property("Value1",  &TWOVALUES::iValue1) 
    .add_property("Value2",  &TWOVALUES::iValue2); 
}; 

w drugiej ręce mam funkcji Pythona zdefiniowane w python_script.py WHI ch bierze instancję tej klasy i coś robi.Na przykład:

def wrapper_function(instance): 
    result = instance.Addition() 
    myfile = open(r"C:\...\testboostexample.txt", "w") 
    output = 'First variable is {0}, second variable is {1} and finally the addition is {2}'.format(instance.Value1, instance.Value2, result) 
    myfile .write(output) 
    myfile .close() 

Następnie w C++ boku, mogę wywołać tę funkcję, wysyłając jednocześnie wystąpienie mojej klasie, tak:

Py_Initialize(); 

try 
    { 
    TwoValues instance(5, 10); 
    initModuleTestBoost(); 

    object python_script = import("python_script"); 
    object wrapper_function = python_script.attr("wrapper_function"); 
    wrapper_function(&instance); 
    } 
catch (error_already_set) 
    { 
    PyErr_Print(); 
    } 

Py_Finalize(); 

Zalety:

  • Nie potrzebuję budować żadnej biblioteki współdzielonej ani binarnej
  • Jak używam Boost, nie muszę się martwić o zarządzanie pamięcią & odniesienia liczenia
  • Nie używać udostępnionego wskaźnik doładowania (boost :: shared_ptr), aby wskazać na przykład mojej klasie
6

O ile mi wiadomo, nie ma prostego sposobu na osiągnięcie tego.

Aby rozszerzyć Python w C++ bez modułu ani biblioteki pośredniej, wymagałoby to dynamicznego ładowania biblioteki, a następnie importowania funkcji. To podejście jest używane przez moduł ctypes. Aby osiągnąć to samo z C++, trzeba napisać bibliotekę ctypes-like, która rozumie ABI AB dla docelowego kompilatora (ów).

Aby rozszerzyć Pythona bez wprowadzania modułu, można utworzyć bibliotekę pośrednią, która zapewni C API, która otoczy bibliotekę C++. Ta pośrednia biblioteka może być następnie użyta w Pythonie przez ctypes. Chociaż nie zapewnia dokładnej składni wywołania i wprowadza bibliotekę pośrednią, prawdopodobnie byłby to mniejszy wysiłek niż budowanie biblioteki, która mogłaby być bezpośrednio połączona z C++.

Jednakże, jeśli zostanie wprowadzona biblioteka pośrednia, warto skorzystać z Boost.Pythona, SWIG lub innego narzędzia do wiązania języków C++/Python. Podczas gdy wiele z tych narzędzi wprowadzi rozszerzenie za pośrednictwem modułu, często zapewniają one czystsze konwencje wywoływania, lepsze sprawdzanie błędów w procesie wiązania i mogą być łatwiejsze do utrzymania.

+0

Bardzo ładna odpowiedź. Obejmuje wszystko, co chciałem powiedzieć i więcej (więc nie mam zamiaru nawet odpowiadać;) – nneonneo

Powiązane problemy