2013-06-02 12 views
7

Podejrzewam, że istnieje prosta odpowiedź, ale potrzebuję pomocy w rozpoczęciu pracy z Cythonem. Mam istniejącą bazę kodu w C++, którą chcę eksponować w Pythonie przez Cython. Dla każdej klasy, którą chcę eksponować, tworzę cppclass Cython _ClassName i klasę opakowania Pythona ClassName.Jak zwrócić nowe obiekty C++ w Cython?

minmal przykład:

Object.h 
CythonMinimal.pyx 
setup.py 

zawartość Object.h:

class Object { 

public: 

    Object clone() { 
     Object o; 
     return o; 
    } 

}; 

zawartość CythonMinimal.pyx:

cdef extern from "Object.h": 
    cdef cppclass _Object "Object": 
     _Object() except + 
     _Object clone() 


cdef class Object: 

    cdef _Object *thisptr 

    def __cinit__(self): 
     self.thisptr = new _Object() 

    def __dealloc__(self): 
     del self.thisptr 

    def clone(self): 
     return self.thisptr.clone() 

zawartość setup.py

from distutils.core import setup 
from distutils.extension import Extension 
from Cython.Build import cythonize 
from Cython.Distutils import build_ext 

import os 

os.environ["CC"] = "g++-4.7" 
os.environ["CXX"] = "g++-4.7" 


modules = [Extension("CythonMinimal", 
        ["CythonMinimal.pyx"], 
        language = "c++", 
        extra_compile_args=["-std=c++11"], 
        extra_link_args=["-std=c++11"])] 

for e in modules: 
    e.cython_directives = {"embedsignature" : True} 

setup(name="CythonMinimal", 
    cmdclass={"build_ext": build_ext}, 
    ext_modules=modules) 

Jest to błąd pojawia się podczas kompilacji:

cls ~/workspace/CythonMinimal $ python3 setup.py build 
running build 
running build_ext 
cythoning CythonMinimal.pyx to CythonMinimal.cpp 

Error compiling Cython file: 
------------------------------------------------------------ 
... 

    def __dealloc__(self): 
     del self.thisptr 

    def clone(self): 
     return self.thisptr.clone() 
         ^
------------------------------------------------------------ 

    CythonMinimal.pyx:18:27: Cannot convert '_Object' to Python object 
    building 'CythonMinimal' extension 
    creating build 
    creating build/temp.macosx-10.8-x86_64-3.3 
    g++-4.7 -Wno-unused-result -fno-common -dynamic -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -I/usr/local/include -I/usr/local/opt/sqlite/include -I/usr/local/Cellar/python3/3.3.0/Frameworks/Python.framework/Versions/3.3/include/python3.3m -c CythonMinimal.cpp -o build/temp.macosx-10.8-x86_64-3.3/CythonMinimal.o -std=c++11 
    cc1plus: warning: command line option '-Wstrict-prototypes' is valid for C/ObjC but not for C++ [enabled by default] 
    CythonMinimal.cpp:1:2: error: #error Do not use this file, it is the result of a failed Cython compilation. 
    error: command 'g++-4.7' failed with exit status 1 

Zakładam, że _Object.clone musi zwrócić _Object (typ cppclass), ale Objet.clone powinien zwrócić Object (typ Pythona). Ale jak?

+0

mógłbyś possibl y zredukuj to do ściśle minimalnego przykładu (np. nie więcej niż jeden .h plik nagłówkowy), a następnie wysłać tutaj WSZYSTKIE pliki (kod C++, nagłówek .h, setup.py, wrapper cython, aplikacja python)? Ponieważ nie istnieje kompleksowa dokumentacja powiązania Cython/C++, byłoby pomocne dla wielu z nas do współpracy tutaj (lub na [email protected]?), Aby uzyskać jeden minimalny przykład działa. –

+0

Spróbuję skonstruować minimalny przykład. Ale czy nie mam racji, sądząc, że jest to dość ogólne pytanie dla początkujących, a rozwiązanie powinno być oczywiste dla kogoś z doświadczeniem Cython + C++? – clstaudt

+0

Nie ma zbyt wielu doświadczonych programistów w Cython/C++ - i jest mało prawdopodobne, że staną się liczniejsze, o ile dokumentacja nie zostanie poprawiona. Dla mnie osobiście nauka Cython/C++ jest dla mnie bardzo ważna; ale po pierwszej próbie zakończonej nierozwiązanymi problemami odłożyłem dalsze wysiłki. Dlatego chciałbym spróbować na nowo z twoim przykładem ... –

Odpowiedz

5

Wracasz C++ obiektu w funkcji Pythona, który może zwrócić tylko obiekty Pythona:

def clone(self): 
    return self.thisptr.clone() 

zrobić to w ten sposób:

cdef _Object clone(self) except *: 
    return self.thisptr.clone() 

Ale to zależy od tego, co próbujesz robić, prawdopodobnie chcesz zwrócić przedmiot i nie _Object, więc chciałbym zmodyfikować to w ten sposób:

cdef class Object: 
    cdef _Object thisobj 
    cdef _Object *thisptr  

    def __cinit__(self, Object obj=None): 
     if obj: 
      self.thisobj = obj.thisobj.clone() 
     self.thisptr = &self.thisobj 

    def __dealloc__(self): 
     pass 

    def clone(self): 
     return Object(self) 
+0

Prawidłowo, chcę zwrócić 'Object', a nie' _Object' – clstaudt

+0

Myślałem, że to może działać jako ogólne rozwiązanie, nie tylko w specjalny przypadek tego przykładu, w którym istnieje metoda klonowania: 'def __cinit __ (self, _Object obj = None): ...' Ale '__cinit__' nie akceptuje' _Object', ponieważ nie może go przekonwertować na obiekt Pythona. – clstaudt

+2

@ cls Nie można przekazywać obiektów C++ do konstruktorów, jest to niedozwolone, ale można ustawić właściwość po skonstruowaniu obiektu. 'obj = Object(); obj.thisptr = myCppObj; '.W tym celu można utworzyć funkcje opakowania: 'cdef CreateObject (_Object _obj): obj = Object(); obj.thisptr = _obj; return obj; '. –