如何使用 Cython 类型的内存视图接受来自 Python 的字符串?
How to use Cython typed memoryviews to accept strings from Python?
如何编写一个接受字节字符串对象(普通字符串、字节数组或 buffer protocol) as a typed memoryview 之后的其他对象)的 Cython 函数?
根据 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[=12=]ing"))'
'test\x00ing'
但它不适用于普通字符串和其他只读缓冲区对象:
$ python -c 'import test; test.printbuf("test[=13=]ing")'
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 总是将 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((<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[=15=]ing"))'
'test\x00ing'
$ python -c 'import test; test.printbuf("test[=15=]ing")'
'test\x00ing'
是我做错了什么,还是 Cython 不支持将只读缓冲区对象(例如普通字符串)强制转换为类型化的内存视图对象?
尽管文档另有建议,Cython(至少达到 0.22 版)不 支持将只读缓冲区对象强制转换为类型化的内存视图对象。 Cython 总是将 PyBUF_WRITABLE
标志传递给
PyObject_GetBuffer()
,即使它不需要写权限。这会导致只读缓冲区对象引发异常。
我raised this issue on the Cython developer mailing list,甚至包括一个(非常粗糙的)补丁。我从未收到回复,所以我认为 Cython 开发人员对修复此错误不感兴趣。
此问题已在 2018 年 3 月 13 日发布的 Cython 0.28 中修复(PR #1869). The changelog 说:
The const modifier can be applied to memoryview declarations to allow read-only buffers as input.
还有一个新的section in the documentation。
如果您这样编写函数,您提供的示例将在 Cython 0.28 中运行:
cpdef object printbuf(const unsigned char[:] buf):
chars = [chr(x) for x in buf]
print repr(''.join(chars))
如何编写一个接受字节字符串对象(普通字符串、字节数组或 buffer protocol) as a typed memoryview 之后的其他对象)的 Cython 函数?
根据 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[=12=]ing"))'
'test\x00ing'
但它不适用于普通字符串和其他只读缓冲区对象:
$ python -c 'import test; test.printbuf("test[=13=]ing")'
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 总是将 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((<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[=15=]ing"))'
'test\x00ing'
$ python -c 'import test; test.printbuf("test[=15=]ing")'
'test\x00ing'
是我做错了什么,还是 Cython 不支持将只读缓冲区对象(例如普通字符串)强制转换为类型化的内存视图对象?
尽管文档另有建议,Cython(至少达到 0.22 版)不 支持将只读缓冲区对象强制转换为类型化的内存视图对象。 Cython 总是将 PyBUF_WRITABLE
标志传递给
PyObject_GetBuffer()
,即使它不需要写权限。这会导致只读缓冲区对象引发异常。
我raised this issue on the Cython developer mailing list,甚至包括一个(非常粗糙的)补丁。我从未收到回复,所以我认为 Cython 开发人员对修复此错误不感兴趣。
此问题已在 2018 年 3 月 13 日发布的 Cython 0.28 中修复(PR #1869). The changelog 说:
The const modifier can be applied to memoryview declarations to allow read-only buffers as input.
还有一个新的section in the documentation。
如果您这样编写函数,您提供的示例将在 Cython 0.28 中运行:
cpdef object printbuf(const unsigned char[:] buf):
chars = [chr(x) for x in buf]
print repr(''.join(chars))