作者:小菜刀丶 | 来源:互联网 | 2023-05-24 15:21
我如何编写一个Cython函数,它将一个字节串对象(一个普通字符串,一个bytearray或另一个跟在缓冲区协议下的对象)作为一个类型化的内存视图?
根据Unicode和Passing Strings Cython教程页面,以下内容应该有效:
cpdef object printbuf(unsigned char[:] buf):
chars = [chr(x) for x in buf]
print repr(''.join(chars))
它适用于bytearrays和其他可写缓冲区:
$ python -c 'import test; test.printbuf(bytearray("test\0ing"))'
'test\x00ing'
但它不适用于普通字符串和其他只读缓冲区对象:
$ python -c 'import test; test.printbuf("test\0ing")'
Traceback (most recent call last):
File "", line 1, in
File "test.pyx", line 1, in test.printbuf (test.c:1417)
File "stringsource", line 614, in View.MemoryView.memoryview_cwrapper (test.c:6795)
File "stringsource", line 321, in View.MemoryView.memoryview.__cinit__ (test.c:3341)
BufferError: Object is not writable.
查看生成的C代码,Cython总是将PyBUF_WRITABLE
标志传递给PyObject_GetBuffer()
,这解释了异常.
我可以自己手动获取缓冲区对象的视图,但这不方便:
from cpython.buffer cimport \
PyBUF_SIMPLE, PyBUF_WRITABLE, \
PyObject_CheckBuffer, PyObject_GetBuffer, PyBuffer_Release
cpdef object printbuf(object buf):
if not PyObject_CheckBuffer(buf):
raise TypeError("argument must follow the buffer protocol")
cdef Py_buffer view
PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE)
try:
chars = [chr((view.buf)[i])
for i in range(view.len)]
print repr(''.join(chars))
finally:
PyBuffer_Release(&view)
$ python -c 'import test; test.printbuf(bytearray("test\0ing"))'
'test\x00ing'
$ python -c 'import test; test.printbuf("test\0ing")'
'test\x00ing'
我做错了什么,或者Cython不支持将只读缓冲区对象(例如普通字符串)强制转换为类型化的memoryview对象?
1> Richard Hans..:
尽管文件表明,否则,用Cython(至少到0.22版本)并没有支持胁迫只读缓冲区对象为键入memoryview对象.Cython总是将PyBUF_WRITABLE
标志传递给
PyObject_GetBuffer()
,即使它不需要写访问权限.这会导致只读缓冲区对象引发异常.
我在Cython开发人员邮件列表上提出了这个问题,甚至还包括一个(非常粗略的)补丁.我从来没有得到过回复,所以我认为Cython开发人员对修复这个bug并不感兴趣.