如何编写一个Cython函数,以typed memoryview的形式接受一个字节串对象(普通字符串、bytearray或遵循buffer protocol的其他对象)?
根据Unicode and Passing Strings Cython教程页面的说明,以下代码应该可以实现:
cpdef object printbuf(unsigned char[:] buf):
chars = [chr(x) for x in buf]
print repr(''.join(chars))
它适用于字节数组和其他可写缓冲区:
$ 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 "<string>", line 1, in <module>
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总是向PyObject_GetBuffer()传递PyBUF_WRITABLE标志,这解释了异常。
我可以手动获取一个视图到缓冲对象中,但这不太方便。
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((<unsigned char *>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对象?
const
现在可以在Cython 0.28.4中正常工作了。 - winni2k