如何为非连续的内存位置创建memoryview?

11

我在内存中有一个分散的结构,希望将其访问为连续的内存视图。是否有简单的方法可以做到这一点,还是应该实现自己的解决方案?

例如,考虑一个由记录组成的文件格式。每个记录都有一个固定长度的标头,指定记录内容的长度。较高级别的逻辑结构可能分布在多个记录上。如果它能够将自己的分散内存位置视为简单的连续字节数组,那么实现更高级别的结构会更容易。

更新:

似乎Python在内部支持此“分段”缓冲区类型,至少基于此部分文档。但是这仅适用于C API。

更新2:

据我所见,所引用的C API - 称为旧式缓冲区 - 可以满足我的需求,但现在已被弃用,并且在较新版本的Python(3.X)中不可用。在PEP 3118中指定的新缓冲区协议提供了一种表示缓冲区的新方法。该API在大多数用例中更易于使用(其中包括表示的缓冲区不是内存中连续的情况),但不支持此特定用例,在该用例中可以完全自由地布置一维数组(多个大小不同的块)。


1
首先,文件很少是内存结构。其次,为什么以及通过何种方式你需要访问低级内存结构,并且使用Python来完成呢?这个问题似乎更适合C或C++之类的语言,或者其他具有开发控制内存分配和访问的语言。 - alko
1
遍历链表并打印每个数据? - perreal
1
如果您使用 mmap(在 Python 中也可用)将文件映射,则该文件将成为内存结构。是的,可以遍历链接列表,但关键是我想使用像 memoryview 接口一样的简单接口访问它。我认为这是可能的,因为文档提到您可以使用它来访问非连续数据(例如 NumPy 数组)。 - molnarg
2
不容易,但是可能可以使用所谓的PIL-style buffers - Fred Foo
关于mmap,段必须具有内存页面粒度。虽然这是个不错的技巧,但是是已经被使用过了! - Dima Tisnek
1个回答

2

首先 - 我假设您只是想在纯Python中完成这个任务,而不是使用C扩展。因此,我假设您已经将您感兴趣的不同记录加载到一组Python对象中,您的问题是您希望查看跨越这些对象的更高级别结构,并且这些结构在对象中分散到各个位置。

那么,您不能将每个记录简单地加载到字节数组类型中吗?然后,您可以使用Python数组的切片来创建一个新数组,其中仅包含您感兴趣的高级结构的数据。然后,您将拥有一个仅包含您感兴趣的数据的单个字节数组,并且可以以任何您想要的方式打印或操作它。

因此,类似于以下内容:

a = bytearray(b"Hello World") # put your records into byte arrays like this
b = bytearray(b"Stack Overflow")
complexStructure = bytearray(a[0:6]+b[0:]) # Slice and join arrays to form
                                           # new array with just data from your
                                           # high level entity
print complexStructure

当然,您仍需知道高级结构在记录中的位置才能正确切割数组,但无论如何您都需要知道这一点。
编辑:
请注意,对列表进行切片并不会复制列表中的数据,它只是创建对数据的新引用集。
>>> a = [1,2,3]
>>> b = a[1:3]
>>> id(a[1])
140268972083088
>>> id(b[0])
140268972083088

然而,对列表b的更改不会改变a,因为b是一个新列表。如果要自动在原始列表中进行更改,则需要创建一个更复杂的对象,其中包含列表与原始记录,并以这样的方式隐藏它们,以便能够决定当用户查看复杂结构并尝试修改/查看列表及其元素时,需要更改或查看哪个列表和哪个列表元素。因此,可以考虑以下内容:

class ComplexStructure():
    def add_records(self,record):
        self.listofrecords.append(record)

    def get_value(self,position):
        listnum,posinlist = ... # formula to figure out which list and where in 
                                # list element of complex structure is
        return self.listofrecords[listnum][record]

    def set_value(self,position,value):
        listnum,posinlist = ... # formula to figure out which list and where in 
                                # list element of complex structure is
        self.listofrecords[listnum][record] = value

虽然这不是你所希望的简单方法,但它应该能够满足你的需求。


这是某些用例的好解决方案,确实如此。与memoryview的主要区别是:1.这需要复制数据2.当修改新的数据结构时,不会影响原始缓冲区,必须将修改内容复制回去。在理想的解决方案中,我希望看到这两个属性。 - molnarg
molnarg:添加了一个编辑来处理您的额外两个属性。 - Tommy
谢谢,这似乎是唯一的解决方案,因为使用内置API可能无法实现。 - molnarg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接