python memory-management cython pybuffer pep3118

python - Usando la API de búfer en Cython



memory-management pybuffer (1)

Estoy trabajando con una biblioteca de C que repetidamente llama a un puntero de función proporcionado por el usuario para obtener más datos. Me gustaría escribir un contenedor de Cython de tal manera que la implementación de Python de esa devolución de llamada pueda devolver cualquier tipo de datos razonable como str , bytearray , archivos de memoria asignados, etc. (específicamente, admite la interfaz Buffer ). Lo que tengo hasta ahora es:

from cpython.buffer cimport PyBUF_SIMPLE from cpython.buffer cimport Py_buffer from cpython.buffer cimport PyObject_GetBuffer from cpython.buffer cimport PyBuffer_Release from libc.string cimport memmove cdef class _callback: cdef public object callback cdef public object data cdef uint16_t GetDataCallback(void * userdata, uint32_t wantlen, unsigned char * data, uint32_t * gotlen): cdef Py_buffer gotdata box = <_callback> userdata gotdata_object = box.callback(box.data, wantlen) if not PyObject_CheckBuffer(gotdata_object): # sulk return 1 try: PyObject_GetBuffer(gotdata_object, &gotdata, PyBUF_SIMPLE) if not (0 < gotdata.len <= wantlen): # sulk return 1 memmove(data, gotdata.buf, gotdata.len) return 0 finally: PyBuffer_Release(&gotdata)

El código que quiero escribir produciría un código C equivalente, pero se vería así:

from somewhere cimport something from libc.string cimport memmove cdef class _callback: cdef public object callback cdef public object data cdef uint16_t GetDataCallback(void * userdata, uint32_t wantlen, unsigned char * data, uint32_t * gotlen): cdef something gotdata box = <_callback> userdata gotdata = box.callback(box.data, wantlen) if not (0 < gotdata.len <= wantlen): # sulk return 1 memmove(data, gotdata.buf, gotdata.len) return 0

El código C generado se parece a lo que creo que debería estar haciendo; pero esto parece estar cavando en la API de Python innecesariamente. ¿Proporciona Cython una mejor sintaxis para lograr este efecto?


Si desea admitir todo lo que implemente cada variación de la interfaz de búfer de estilo nuevo o antiguo, entonces tiene que usar la API de C.

Pero si no te importan los buffers de estilo antiguo, casi siempre puedes usar una vista de memoryview :

Las vistas de memoria de Cython admiten casi todos los objetos que exportan la interfaz de los nuevos buffers de estilo de Python. Esta es la interfaz de búfer descrita en PEP 3118. Las matrices NumPy son compatibles con esta interfaz, al igual que las matrices Cython. El "casi todo" se debe a que la interfaz del búfer de Python permite que los elementos de la matriz de datos sean punteros; Las vistas de memoria de Cython aún no admiten esto.

Por supuesto, esto incluye str (o, en 3.x, bytes ), bytearray , etc. Si siguió el enlace, puede observar que se vincula a la misma página para explicar qué admite el enlace que ha vinculado para explicar qué desea. apoyo.

Para matrices 1D de caracteres (como str ), es:

cdef char [:] gotdata