从C结构创建PyBuffer

1 投票
1 回答
1747 浏览
提问于 2025-04-15 15:52

编辑:在重新阅读我最初的问题后,我很快意识到这个问题表述得很糟糕,含糊不清,太让人困惑,根本无法得到一个好的答案。这是我在午休结束时匆忙提问的结果。希望这次能更清楚一些:

我想把一个简单的C语言结构体暴露给Python(3.x),这样我就可以从中获取一个MemoryView。我要暴露的结构体大概是这样的:

struct ImageBuffer {
    void* bytes;
    int row_count;
    int bytes_per_row;
};

我希望脚本编写者能够像这样访问数据:

img_buffer = img.get_buffer()
img_buffer[1::4] = 255 # Set every Red component to full intensity

不幸的是,关于这些结构体的C API的现有文档非常稀少,有些地方自相矛盾,还有些地方完全错误(文档中的函数签名和头文件中的不匹配等等)。因此,我对如何最好地暴露这个结构体并没有很好的想法。此外,我希望避免使用第三方库来实现应该是核心库的一部分的功能,但我觉得PyBuffer的功能仍然相当不成熟,也许像NumPy这样的库会是更好的选择。

有没有人对此有什么建议?

1 个回答

2

要让你的扩展类型支持缓冲区协议,需要实现一系列方法,具体内容可以在这里找到:http://docs.python.org/3.1/c-api/typeobj.html#buffer-object-structures

我知道这些文档写得比较复杂,所以我建议你可以从现有的C类型的缓冲区API实现入手,比如官方Python源代码中的bytesobject.c或bytearrayobject.c。

不过,请注意,缓冲区协议并不能让你使用一些高级的表示法,比如你提到的:img_buffer[1::4] = 255 在memoryview对象上是无法使用的。

补充:更准确地说,memoryviews支持某些类型的切片赋值,但并不是所有的。此外,它们也不够“聪明”,无法理解将255赋值给切片实际上是想让这个字节值重复。举个例子:

>>> b = bytearray(b"abcd")
>>> m = memoryview(b)
>>> m[0:2] = b"xy"
>>> b
bytearray(b'xycd')
>>> m[0:2] = 255
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'int' does not support the buffer interface
>>> m[0:2] = b"x"
Traceback (most recent call last):
  File "", line 1, in 
ValueError: cannot modify size of memoryview object
>>> m[0::2] = b"xy"
Traceback (most recent call last):
  File "", line 1, in 
NotImplementedError

撰写回答