2013-06-02 11 views
7

Sospetto che ci sia una risposta facile a questo, ma ho bisogno di aiuto per iniziare con Cython. Ho una base di codice C++ esistente che voglio esporre a Python tramite Cython. Per ogni classe che desidero esporre, creo una cppclass Cython _ClassName e la classe wrapper Python ClassName.Come restituire nuovi oggetti C++ in Cython?

Un esempio minmal:

Object.h 
CythonMinimal.pyx 
setup.py 

contenuto Object.h:

class Object { 

public: 

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

}; 

contenuto 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() 

contenuto 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) 

Questo è l'errore che ottengo quando si compila:

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 

Presumo che _Object.clone ha la necessità di restituire un (tipo cppclass) _Object, ma Objet.clone dovrebbe restituire un (tipo Python) Object. Ma come?

+0

Potresti y ridurre questo ad un esempio strettamente minimale (ad es. non più di un file di intestazione .h, e pubblica qui TUTTI i file (codice C++, .h header, setup.py, cython wrapper, applicazione python)? Poiché non esiste una documentazione completa del binding Cython/C++, sarebbe utile per molti di noi collaborare qui (o su [email protected]?) Per ottenere un esempio minimo in esecuzione. –

+0

Proverò a creare un esempio minimo. Ma ho sbagliato a pensare che questa è una domanda per principianti abbastanza generale e la soluzione dovrebbe essere ovvia per qualcuno con esperienza Cython + C++? – clstaudt

+0

Non ci sono molti sviluppatori Cython/C++ esperti ed è improbabile che diventeranno più numerosi a meno che la documentazione non sia migliorata. Per me personalmente, l'apprendimento di Cython/C++ è in cima alla mia agenda; ma dopo un primo tentativo terminato con problemi irrisolti, ho rinviato ulteriori sforzi. Pertanto, vorrei riprovare con il tuo esempio ... –

risposta

5

si restituisce un oggetto C++ in una funzione di pitone che è permesso per restituire solo oggetti Python:

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

Make it questo:

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

ma dipende da quello che stai cercando probabilmente devi restituire Object e non _Object, quindi modificherei in questo modo:

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

Corretto, voglio restituire 'Object', non' _Object' – clstaudt

+0

Ho pensato che questo potesse funzionare come soluzione generale, non solo in il caso speciale di questo esempio in cui esiste un metodo clone: ​​'def __cinit __ (self, _Object obj = None): ...' Ma '__cinit__' non accetta un' _Object' perché non può convertirlo in un oggetto Python. – clstaudt

+2

@cls Non è possibile passare oggetti C++ ai costruttori, questo non è consentito, ma è possibile impostare la proprietà dopo la costruzione dell'oggetto. 'obj = Object(); obj.thisptr = myCppObj; '.È possibile creare funzioni wrapper per questo: 'cdef CreateObject (_Object _obj): obj = Object(); obj.thisptr = _obj; return obj; '. –

Problemi correlati