我有一个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, )
和(8, )
都是一维的,(10, 2)
和(20, 1)
都是二维的。 - 对于 C 连续数组,步幅元组中的最后一个元素表示内存视图中项的项大小。这并不总是正确的:有时值被填充,然后它会大于实际的 itemsize - 但在大多数情况下,它代表 itemsize。
因此,您不仅希望将内存视图展平化,而且还应该将其展平,并且项大小为 1。
在 Python 3.3 中,添加了memoryview.cast
方法,使扁平化数组变得微不足道:
cast(format[, shape])
将内存视图转换为新的格式或形状。 形状默认为 [byte_length//new_itemsize],这意味着结果视图将是一维的。返回值是一个新的内存视图,但缓冲区本身不会被复制。支持的转换为 1D -> C 连续和 C 连续 -> 1D。
目标格式限制为结构语法中的单个元素本机格式。其中一种格式必须是字节格式("B"、"b"或"c")。结果的字节长度必须与原始长度相同。
所以它只在投射到字符(c
)、无符号字符(B
)或有符号字符(b
)并且它是C连续的时才有效。
>>> 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, )