Подтвердить что ты не робот

Использование API-интерфейса буфера в Cython

Я работаю с библиотекой C, которая неоднократно вызывает указатель на функцию, предоставленную пользователем, чтобы получить больше данных. Я хотел бы написать оболочку Cython таким образом, что реализация этого обратного вызова на Python может вернуть любой разумный тип данных, такой как str, bytearray, файлы с отображением памяти и т.д. (В частности, поддерживает Интерфейс буфера). что я до сих пор:

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 выглядит так, как я думаю, он должен делать; но это похоже на то, что в API Python необязательно. Обеспечивает ли Cython лучший синтаксис для достижения этого эффекта?

4b9b3361

Ответ 1

Если вы хотите поддерживать все, что реализует все варианты интерфейса буфера нового стиля или старого стиля, тогда вам нужно использовать C API.

Но если вам не нужны буферы старого стиля, вы почти всегда можете использовать memoryview:

Cython memoryviews поддерживает почти все объекты, экспортирующие интерфейс буферов нового стиля Python. Это интерфейс буфера, описанный в PEP 3118. Массивы NumPy поддерживают этот интерфейс, как и массивы Cython. "Почти все" связано с тем, что интерфейс буфера Python позволяет элементам в массиве данных быть указателями; Cython memoryviews еще не поддерживает это.

Это, конечно, включает str (или в 3.x, bytes), bytearray и т.д. - если вы следовали за ссылкой, вы можете заметить, что она ссылается на одну страницу, чтобы объяснить, что она поддерживает которые вы связали, чтобы объяснить, что вы хотите поддержать.

Для 1D массивов символов (например, str) это:

cdef char [:] gotdata