Как сгладить память?

У меня есть memoryview с нетривиальными шагами вроде следующего:

>>> mv.strides
(96, 32, 8)

Я хочу написать это memoryview к сокету, но моя сетевая библиотека, кажется, ожидает просмотра памяти с mv.strides == (1,), Есть ли способ в Python, чтобы сгладить это memoryview?

>>> flatten(mv).strides
(1,)

В идеале это не повлияет на байты и не потребует копии. Я мог бы сделать это с помощью NumPy, но я бы предпочел, чтобы все было по-другому.

Редактировать: вот код, который производит такое представление памяти

In [1]: import numpy as np
In [2]: x = np.ones((2, 3, 4))
In [3]: x.data
Out[3]: <memory at 0x7f371aa849a8>

In [4]: x.data.strides
Out[4]: (96, 32, 8)

1 ответ

Решение

Просто для пояснения, вы, вероятно, знаете это, но я думаю, что лучше убедиться:

  • Длина шага кортежа представляет количество измерений, поэтому (1, ) а также (8, ) оба одномерные и (10, 2) а также (20, 1) оба двумерные.
  • Для C-смежных массивов последний элемент в кортеже шагов представляет размер элементов в вашем виде на память. Это не всегда правильно: иногда значения дополняются, тогда это будет больше, чем фактический размер элементов, но в большинстве случаев он представляет размер элементов.

Таким образом, вы не только хотите, чтобы ваш просмотр памяти был сглажен, но он должен быть сглажен и иметь размер элементов 1.

В Python 3.3 memoryview.cast добавлен метод, который делает выравнивание вашего массива тривиальным:

cast(format[, shape])

Приведите представление о памяти к новому формату или форме. форма по умолчанию имеет значение [byte_length//new_itemsize], что означает, что представление результатов будет одномерным. Возвращаемое значение - это новое представление памяти, но сам буфер не копируется. Поддерживаются следующие типы приведений: 1D -> C-смежный и C-смежный -> 1D.

Формат назначения ограничен собственным форматом одного элемента в структурном синтаксисе. Один из форматов должен быть байтовым форматом ("B", "b" или "c"). Длина в байтах результата должна совпадать с исходной длиной.

Так что это работает только если вы бросили на char (c), беззнаковый символ (B) или подписанные символы (b) и это С-смежно.

>>> import numpy as np

>>> memview = memoryview(np.ones((2, 3, 4)))
>>> memview.cast('b').strides   # or 'B' or 'c'
(1, )

Однако это сглаживается и интерпретируется как 1-байтовые значения. Если вы просто хотите, чтобы он был сплющен, вам нужно снова привести его к исходному типу:

>>> memview.cast('b').cast(memview.format)

Это будет одномерно, но не будет (1, ) потому что число с плавающей запятой составляет 8 байт (по крайней мере, если это float64):

>>> memview.cast('b').cast(memview.format).strides
(8, )
Другие вопросы по тегам