型指定された memoryviewとしてバイト文字列オブジェクト (通常の文字列、bytearray、またはbuffer protocolに従う別のオブジェクト) を取る Cython 関数を作成するにはどうすればよいですか?
Unicode and Passing Strings Cython チュートリアル ページによると、次のように動作するはずです。
cpdef object printbuf(unsigned char[:] buf):
chars = [chr(x) for x in buf]
print repr(''.join(chars))
bytearray やその他の書き込み可能なバッファーでは機能します。
$ 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 は常に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\0ing"))'
'test\x00ing'
$ python -c 'import test; test.printbuf("test\0ing")'
'test\x00ing'
何か間違ったことをしていますか、それとも Cython は型指定された memoryview オブジェクトへの読み取り専用バッファ オブジェクト (通常の文字列など) の強制をサポートしていませんか?