2013-04-20 12 views
20

Sto lavorando con una libreria C che richiama ripetutamente un puntatore funzione fornito dall'utente per ottenere più dati. Mi piacerebbe scrivere un wrapper Cython in modo tale che l'implementazione Python di tale callback possa restituire qualsiasi tipo di dati ragionevole come str, bytearray, file mappati in memoria e così via (in particolare, supporta lo Buffer interface). quello che ho finora è:Utilizzo dell'API del buffer in Cython

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) 

Il codice che voglio scrivere produrrebbe codice C equivalente, ma simile a questa:

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 

Il codice C generato assomiglia a quello che penso dovrebbe fare; ma questo sembra come scavare inutilmente nell'API Python. Cython fornisce una sintassi migliore per ottenere questo effetto?

risposta

2

Se si desidera supportare tutto ciò che implementa ogni variante dell'interfaccia del buffer di nuovo stile o vecchio stile, è necessario utilizzare l'API C.

Ma se non si cura di buffer vecchio stile, è quasi sempre possibile utilizzare un memoryview:

supporto Cython memoryviews quasi tutti gli oggetti che esportano l'interfaccia di Python buffer di nuovo stile. Questa è l'interfaccia buffer descritta in PEP 3118. Gli array NumPy supportano questa interfaccia, così come gli array Cython. Il "quasi tutto" è perché l'interfaccia del buffer Python consente agli elementi dell'array di dati di essere puntatori stessi; Le visioni di memoria Cython non lo supportano ancora.

Questo, naturalmente, comprende str (o, in 3.x, bytes), bytearray, ecc, se avete seguito il link, si può notare che si collega alla stessa pagina per spiegare quello che sostiene che si è collegato per spiegare cosa vuoi sostenere.

Per array 1D di caratteri (come str), è:

cdef char [:] gotdata