Получение указателя на представление памяти 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

Пара предупреждений:

  1. Помни что bytes не является изменяемым, и если вы попытаетесь изменить это представление памяти, это может вызвать проблемы
  2. 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]
Другие вопросы по тегам