Как использовать Cython typed memoryviews для приема строк из Python?
как я могу написать функцию Cython, которая принимает объект Byte string (нормальная строка, bytearray или другой объект, следующий за буфера протокола) в качестве набирается memoryview?
по словам Unicode и передача строк страница учебника 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("testing"))'
'testx00ing'
но это не работает для обычных строк и другие буферные объекты только для чтения:
$ python -c 'import test; test.printbuf("testing")'
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("testing"))'
'testx00ing'
$ python -c 'import test; test.printbuf("testing")'
'testx00ing'
Я делаю что-то неправильно, или Cython не поддерживает принуждение только для чтения буферных объектов (таких как обычные строки) в типизированные объекты memoryview?
2 ответов
несмотря на документацию, предлагающую иное, Cython (по крайней мере, до версии 0.22) делает не поддержка принуждения только для чтения буферных объектов в типизированные объекты memoryview. Cython всегда проходит PyBUF_WRITABLE
флаг
PyObject_GetBuffer()
, даже если для этого не нужен доступ на запись. Это заставляет буферные объекты только для чтения вызывать исключение.
Я поднял эту проблему в списке рассылки Cython developer, и даже включил (очень грубый) патч. У меня никогда не было ... ответ, поэтому я предполагаю, что разработчики Cython не заинтересованы в исправлении этой ошибки.
эта проблема была исправлена в Cython 0.28, выпущенный 2018-03-13 (PR #1869). The изменений говорит:
модификатор const можно применить к объявлениям memoryview, чтобы разрешить буферы только для чтения в качестве входных данных.
появилась новая раздел в документации.
приведенный вами пример будет работать в Cython 0.28, если вы напишете свою функцию следующим образом:
cpdef object printbuf(const unsigned char[:] buf):
chars = [chr(x) for x in buf]
print repr(''.join(chars))