Использование API буфера в Cython
Я работаю с библиотекой C, которая неоднократно вызывает указатель пользовательской функции, чтобы получить больше данных. Я хотел бы написать оболочку Cython таким образом, чтобы реализация этого обратного вызова на Python могла возвращать любой разумный тип данных, например str
, bytearray
, файлы с отображением в памяти и т. д. (в частности, поддерживает интерфейс Buffer). то, что я до сих пор это:
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)
Код, который я хочу написать, выдает эквивалентный код на C, но выглядит так:
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
Сгенерированный C-код выглядит так, как мне кажется; но это похоже на копание в Python API без необходимости. Предоставляет ли Cython более приятный синтаксис для достижения этого эффекта?
1 ответ
Если вы хотите поддерживать все, что реализует все варианты буферного интерфейса нового или старого стиля, то вам нужно использовать C API.
Но если вы не заботитесь о буферах старого стиля, вы почти всегда можете использовать memoryview
:
Представления памяти Cython поддерживают почти все объекты, экспортирующие интерфейс буферов нового стиля Python. Это интерфейс буфера, описанный в PEP 3118. Массивы NumPy поддерживают этот интерфейс, как и массивы Cython. "Почти все" заключается в том, что интерфейс буфера Python позволяет элементам в массиве данных сами по себе быть указателями; Представления памяти Cython пока не поддерживают это.
Это, конечно, включает в себя str
(или в 3.x, bytes
), bytearray
и т. д. - если вы перешли по ссылке, вы можете заметить, что она ссылается на ту же страницу, чтобы объяснить, что она поддерживает, которую вы связали, чтобы объяснить, что вы хотите поддержать.
Для 1D массивов символов (например, str
), его:
cdef char [:] gotdata