21

我正在使用一个 C 库,该库重复调用用户提供的函数指针以获取更多数据。我想编写一个 Cython 包装器,使得该回调的 Python 实现可以返回任何合理的数据类型,如strbytearray、内存映射文件等(特别是支持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 是否提供更好的语法来实现此效果?

4

1 回答 1

2

如果您想支持实现新式或旧式缓冲区接口的每个变体的所有内容,那么您必须使用 C API。

但是,如果您不关心旧式缓冲区,您几乎总是可以使用 a memoryview

Cython memoryviews 支持几乎所有对象导出 Python 新样式缓冲区的接口。这是 PEP 3118 中描述的缓冲区接口。NumPy 数组支持此接口,Cython 数组也是如此。“几乎所有”是因为 Python 缓冲区接口允许数据数组中的元素本身是指针;Cython 内存视图尚不支持这一点。

这当然包括str(或者,在 3.x 中,bytesbytearray,等等——如果您点击链接,您可能会注意到它链接到同一页面来解释它支持什么,而您链接到解释您想要支持什么。

对于一维字符数组(如str),它是:

cdef char [:] gotdata
于 2014-08-13T08:34:47.870 回答