Как сгладить память?
У меня есть 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, )