有没有一种纯粹的Python方法来转置memoryview
?
Pythonmemoryview
可以表示的不仅仅是一维字节块。它们可以表示多维布局、非连续内存、复杂元素类型等。例如,在下面的代码中:
In [1]: import numpy
In [2]: x = numpy.array([[1, 2], [3, 4]])
In [3]: y = x.T
In [4]: a = memoryview(x)
In [5]: b = memoryview(y)
a
和b
是 2×2 多维内存视图:
In [6]: a.shape
Out[6]: (2, 2)
In [7]: b.shape
Out[7]: (2, 2)
b
表示a
的转置,因此a[i, j]
和b[j, i]
别名相同的内存(即原始x
数组的单元格 i、j(:
In [8]: a[0, 1] = 5
In [9]: b[1, 0]
Out[9]: 5
In [10]: x
Out[10]:
array([[1, 5],
[3, 4]])
NumPy 数组支持简单的转置,但 NumPy 数组并不是多维内存视图的唯一来源。例如,您可以强制转换一维内存视图:
In [11]: bytearr = bytearray([1, 2, 3, 4])
In [12]: mem = memoryview(bytearr).cast('b', (2, 2))
In [13]: mem.shape
Out[13]: (2, 2)
In [14]: mem[1, 0] = 5
In [15]: bytearr
Out[15]: bytearray(b'x01x02x05x04')
memoryview 格式足够灵活,可以表示mem
的转置,就像我们之前的例子中b
a
的那样,但在 memoryview API 中似乎没有一个简单的转置方法。有没有一种纯 Python 的方式来转置任意多维内存视图?
不依赖就没有好方法。使用NumPy,只要内存视图没有子偏移量,它就相当简单:
transposed = memoryview(numpy.asarray(orig_memoryview).T)
orig_memoryview
可以由任何东西支持——它后面不必有一个 NumPy 数组。
与其他答案不同,生成的内存视图由与原始内存视图相同的内存支持。例如,使用以下多维内存视图:
In [1]: import numpy
In [2]: arr = numpy.array([[1, 2], [3, 4]])
In [3]: mem = memoryview(arr)
我们可以转置它:
In [4]: transposed = memoryview(numpy.asarray(mem).T)
并写入转置的内存视图影响原始数组:
In [5]: transposed[0, 1] = 5
In [6]: arr
Out[6]:
array([[1, 2],
[5, 4]])
在这里,写入单元格 0,转置的 1 对应于原始数组的单元格 1、0。
这不依赖于由 NumPy 数组支持的原始内存视图。它适用于由其他内容支持的内存视图,例如bytearray
s:
In [7]: x = bytearray([1, 2, 3, 4])
In [8]: y = memoryview(x).cast('b', (2, 2))
In [9]: transposed = memoryview(numpy.asarray(y).T)
In [10]: transposed[0, 1] = 5
In [11]: y[1, 0]
Out[11]: 5
In [12]: x
Out[12]: bytearray(b'x01x02x05x04')
如果没有 NumPy 或类似的依赖项,我看不到一个好方法。最接近好方法是使用 ctypes,但您需要为此对Py_buffer
结构布局进行硬编码,并且Py_buffer
结构的确切布局没有文档。(字段顺序和类型与记录字段的顺序或记录字段的类型不完全匹配。此外,对于具有子偏移量的 PIL 样式数组,如果不复制数据,就无法转置内存视图。
从好的方面来说,大多数情况下,你要处理多维内存视图,你已经有了转置它们所需的依赖关系。
这可能有助于您:
>>> import numpy as np
>>> import array
>>> a = array.array('l', [-11111111, 22222222, -33333333, 44444444])
>>> m = memoryview(a)
>>> m_copy = np.array(m)[np.newaxis]
>>> m_copy
array([[-11111111, 22222222, -33333333, 44444444]])
>>> m_copy.T
array([[-11111111],
[ 22222222],
[-33333333],
[ 44444444]])
不使用 numpy:
import array
a = array.array('l', [-11111111, 22222222, -33333333, 44444444])
print(a)
#output:
array('l', [-11111111, 22222222, -33333333, 44444444])
m = memoryview(a)
a = [[x for x in m]]
result = list(map(list, zip(*a)))
print(result)
#output:
[[-11111111], [22222222], [-33333333], [44444444]]