2012-08-30 53 views
19
cdef extern from "Foo.h": 
    cdef cppclass Bar: 
     pass 

cdef class PyClass: 
    cdef Bar *bar 

    def __cinit__(self, Bar *b) 
     bar = b 

Esto siempre me va a dar algo como:
Cannot convert Python object argument to type 'Bar *'Paso C++ puntero como argumento en la función Cython

¿Hay una manera de lograr esto, o tengo que extraer de todo, desde un objeto Bar, crear un equivalente de Python, pasarlo, y luego reconstruirlo en PyClass?

Respuesta

5

Para cada clase cdef crear una función cdef global que actúa como un constructor, CefResponse es objeto de C++, PyResponse una pitón equivalente de un objeto de C++:

cdef object CreatePyResponse(CefRefPtr[CefResponse] cefResponse): 

    pyResponse = PyResponse() 
    pyResponse.cefResponse = cefResponse 
    return pyResponse 

cdef class PyResponse: 

    cdef CefRefPtr[CefResponse] cefResponse 

    def GetStatus(self): 

     return (<CefResponse*>(self.cefResponse.get())).GetStatus() 

Así que en lugar de resp = PyResponse(cppObject) llamada resp = CreatePyResponse(cppObject).

Ejemplo tomado de CEF Python: https://code.google.com/p/cefpython/source/browse/cefpython/response.pyx?r=0250b65e046a

2

clase Python acepta argumentos Python. Para pasar un C++ argumento de que necesita para envolverlo:

# distutils: language = c++ 

cdef extern from "Foo.h" namespace "baz": 
    cdef cppclass Bar: 
     Bar(double d) 
     double get() 

cdef class PyBar: # wrap Bar class 
    cdef Bar *thisptr 
    def __cinit__(self, double d): 
     self.thisptr = new Bar(d) 
    def __dealloc__(self): 
     del self.thisptr 
    property d: 
     def __get__(self): 
      return self.thisptr.get() 

PyBar casos se pueden utilizar como cualquier otro pitón objetos tanto desde Cython y Python puro:

class PyClass: 
    def __init__(self, PyBar bar): 
     self.bar = bar 

print(PyClass(PyBar(1)).bar.d) 
9

me encontré con este problema tratando de envolver Código C con estructuras como clases de python. El problema parece ser que la función "especial" que incluye __init__ y __cinit__ debe declararse como def en lugar de cdef. Esto significa que se pueden llamar desde python normal, por lo que los parámetros de tipo se ignoran de manera efectiva y todo se trata como un objeto.

En la respuesta de J.F. Sebastian, la solución no es la envoltura: una doble es un tipo numérico básico y, por lo tanto, hay una conversión predeterminada entre el tipo C/C++ y el objeto Python. La respuesta de Czarek es básicamente correcta: necesitas usar un modismo de constructor falso, usando una función global. No es posible utilizar un decorador de @staticmethod, ya que no se pueden aplicar a las funciones de cdef. La respuesta parece más simple en el ejemplo original proporcionado.

cdef extern from "Foo.h": 
    cdef cppclass Bar: 
     pass 

cdef class PyClass: 
    cdef Bar *bar 

cdef PyClass_Init(Bar *b): 
    result = PyClass() 
    result.bar = b 
    return result 
+3

En versiones recientes de Cython (a partir de al menos 0,22), el decorador @staticmethod se puede aplicar sobre las funciones CDEF, así que ahora se puede hacer que el creador mundial funcionar en una clase estática uno para una organización más ordenada. – Dologan

+0

'Bar' clase C++ no es un tipo numérico básico y no hay una conversión predeterminada. – jfs

+0

@ J.F.Sebastian ¿Podría explicar a qué se refiere? Bar no tiene que ser un tipo numérico básico para almacenar un puntero al mismo. – Amoss

6

Como de Cython 0.21 ha sido posible declarar cdef métodos con el @staticmethod decorador. Esto permite que los métodos estáticos creador que toman argumentos no Python:

cdef extern from "Foo.h": 
    cdef cppclass Bar: 
     pass 

cdef class PyClass: 
    cdef Bar *bar 

    @staticmethod 
    cdef create(Bar *bar): 
     cdef PyClass pc = PyClass() 
     pc.bar = bar 
     return pc 
Cuestiones relacionadas