2013-04-20 5 views
20

Ich arbeite mit einer C-Bibliothek, die wiederholt einen benutzerdefinierten Funktionszeiger ruft, um mehr Daten zu erhalten. Ich möchte einen Cython-Wrapper so schreiben, dass die Python-Implementierung dieses Callbacks jeden vernünftigen Datentyp wie str, bytearray, Speicherabbilddateien usw. zurückgeben kann (unterstützt speziell die Buffer interface). was ich bisher habe, ist:Verwenden der Puffer-API 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) 

Der Code, den ich wollen Äquivalent C-Code zu schreiben, produzieren würde, aber wie folgt aussehen:

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 

Der C-Code erzeugt aussieht, was ich denke, es sollte tun; aber das scheint sich in der Python API unnötig herumzuwühlen. Bietet Cython eine schönere Syntax, um diesen Effekt zu erzielen?

Antwort

2

Wenn Sie alles unterstützen möchten, das jede Variante der neuen oder alten Pufferschnittstelle implementiert, müssen Sie die C-API verwenden.

Aber wenn Sie nicht über die alten Stil Puffer kümmern, können Sie fast verwenden immer ein memoryview:

Cython memoryviews Unterstützung fast alle Objekte die Schnittstelle von Python neuen Stil Puffer zu exportieren. Dies ist die in PEP 3118 beschriebene Pufferschnittstelle. NumPy-Arrays unterstützen diese Schnittstelle ebenso wie Cython-Arrays. Das "fast alles" ist, weil das Python-Puffer-Interface den Elementen im Daten-Array erlaubt, selbst Zeiger zu sein; Cython memoryviews unterstützen dies noch nicht.

Dazu gehören natürlich str (oder, in 3.x, bytes), bytearray, etc-wenn Sie auf den Link gefolgt, können Sie feststellen, dass es auf die gleiche Seite Links zu erklären, was es unterstützt, dass Sie verbunden um zu erklären, was Sie unterstützen möchten.

Für 1D-Arrays von Zeichen (wie str), es ist:

cdef char [:] gotdata