Получение указателя на представление памяти python на байтовом объекте
У меня есть питон memoryview
указывая на bytes
объект, на котором я хотел бы выполнить некоторую обработку в Cython.
Моя проблема:
- поскольку
bytes
объект не доступен для записи, Cython не позволяет создавать типизированное (Cython) представление памяти из него - Я не могу использовать указатели, потому что я не могу получить указатель на начало просмотра памяти
Пример:
В питоне:
array = memoryview(b'abcdef')[3:]
В цифоне:
cdef char * my_ptr = &array[0]
не в состоянии скомпилировать с сообщением:Cannot take address of Python variable
cdef char[:] my_view = array
терпит неудачу во время выполнения с сообщением:BufferError: memoryview: underlying buffer is not writable
Как решить это?
3 ответа
Хорошо, после рытья через Python API я нашел решение, чтобы получить указатель на bytes
буфер объекта в памяти (здесь он называется bytes_view = memoryview(bytes())
). Может быть, это помогает кому-то еще:
from cpython.buffer cimport PyObject_GetBuffer, PyBuffer_Release, PyBUF_ANY_CONTIGUOUS, PyBUF_SIMPLE
cdef Py_buffer buffer
cdef char * my_ptr
PyObject_GetBuffer(bytes, &buffer, PyBUF_SIMPLE | PyBUF_ANY_CONTIGUOUS)
try:
my_ptr = <char *>buffer.buf
# use my_ptr
finally:
PyBuffer_Release(&buffer)
Используя bytearray
(согласно ответу @CheeseLover), вероятно, является правильным способом ведения дел. Мой совет будет работать исключительно в bytearrays
тем самым избегая временных преобразований. Тем не мение:
char*
может быть непосредственно создан из строки Python (или bytes
) - см. конец связанного раздела:
cdef char * my_ptr = array
# you can then convert to a memoryview as normal in Cython
cdef char[:] mview = <char[:len(array)]>my_ptr
Пара предупреждений:
- Помни что
bytes
не является изменяемым, и если вы попытаетесь изменить это представление памяти, это может вызвать проблемы my_ptr
(и поэтомуmview
) действительны только до тех пор, покаarray
действителен, поэтому обязательно сохраните ссылку наarray
до тех пор, пока вам нужен доступ к данным,
Ты можешь использовать bytearray
создать изменчивое представление памяти. Обратите внимание, что это не изменит строку, только bytearray
data = bytearray('python')
view = memoryview(data)
view[0] = 'c'
print data
# cython
Если вы не хотите, чтобы просмотр памяти Cython не выполнялся с "базовым буфером недоступен для записи", вам просто не следует запрашивать доступный для записи буфер. Как только вы окажетесь в домене C, вы сможете вкратце справиться с этой возможностью записи. Так что это работает:
cdef const unsigned char[:] my_view = array
cdef char* my_ptr = <char*>&my_view[0]