首页 > 解决方案 > 在纯 Python 中转置“memoryview”

问题描述

有没有一种纯粹的 Python 方式来转置 a memoryview


Python memoryviews可以表示的不仅仅是一维字节块。它们可以表示多维布局、非连续内存、复杂元素类型等等。例如,在以下代码中:

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'\x01\x02\x05\x04')

memoryview 格式足够灵活,可以表示 的转置mem,就像我们b之前a的示例中那样,但是 memoryview API 中似乎没有简单的转置方法。是否有转置任意多维内存视图的纯 Python 方法?

标签: pythonmemoryview

解决方案


没有依赖就没有好办法。使用 NumPy,它相当简单,只要 memoryview 没有子偏移量

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)

并写入转置的 memoryview 会影响原始数组:

In [5]: transposed[0, 1] = 5

In [6]: arr
Out[6]: 
array([[1, 2],
       [5, 4]])

这里,写入转置的单元格 0, 1 对应于原始数组的单元格 1, 0。

这不依赖于由 NumPy 数组支持的原始内存视图。它适用于由其他事物支持的内存视图,例如bytearrays:

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'\x01\x02\x05\x04')

如果没有 NumPy 或类似的依赖项,我看不到好方法。最接近好方法的是使用 ctypes,但您需要为此硬编码Py_buffer结构布局,并且Py_buffer结构的确切布局没有记录。(字段顺序和类型记录字段的顺序或使用.数据。

从好的方面来说,在处理多维内存视图的大多数情况下,您已经拥有了转置它们所需的依赖项。


推荐阅读