为什么无法从数组对象获取Py_buffer?
Python的文档里明确说明了array符合缓冲区接口的标准。文档甚至建议不要使用buffer_info()这个方法。但是当我尝试在C/C++代码中用PyObject_GetBuffer()获取一个Py_Buffer,或者使用Python的memoryview时,却遇到了失败。
比如,在Python中(我用的是2.7版本):
>>> a = array.array('c')
>>> memoryview(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot make memory view because object does not have the buffer interface
实际上,当我搜索Python的代码库时,只有bytearrayobject(bytearray)、memoryobject(memoryview)和stringobject(str)这几个对象上设置了需要的Py_TPFLAGS_HAVE_NEWBUFFER标志。根据我的理解,文档是错的;array并不支持缓冲区接口。
我可以使用支持缓冲区接口的bytearray,但问题是我需要array的fromfile()方法来读取一个可以在我的C/C++代码中使用的缓冲区。
有没有其他方法可以让我将文件读入一个缓冲区,并且能在C代码中使用这个缓冲区,而不涉及内存复制?(我想处理大型二进制文件,复制不是一个理想的选择)。
2 个回答
Python 2.6及以上版本有两种不同的缓冲区接口,就像它有两种不同的类类型一样:经典版本和Python 3版本。
支持缓冲区接口的对象有字符串和数组。字符串对象以字节为基础的形式展示字符内容。而数组只能通过旧式的缓冲区接口来展示它的内容。在Python 3中,这个限制就不存在了,因为可以从数组构建内存视图对象。
在Python 2.7的代码中,你可以使用buffer
函数来处理旧式缓冲区,使用memoryview
来处理新式缓冲区。而Python 3只支持后者。
在Python 2的C API中也有类似的区分;PyObject_GetBuffer
是用于新缓冲区接口的,PyBuffer_FromObject
/PyBuffer_FromReadWriteObject
是用于旧缓冲区接口的(并且应该适用于数组)。想了解更多信息,请查看上面的链接。
memoryview
这个东西只能在支持 Python 3 缓冲区接口的对象上使用。在 Python 3 中,array.array
是支持的,但在 Python 2.7 中就不支持了。如果你遇到这个问题,可以考虑提交一个错误报告。简单来说,如果你想要使用这个功能,可以直接用 bytearray
(或者如果只是想读取的话,可以用 str
)。这两者都能很好地支持 memoryview
。