检查memoryview 上的文档:
memoryview 对象允许 Python 代码访问支持缓冲区协议的对象的内部数据,而无需复制。
类内存视图(obj)
创建一个引用 obj 的 memoryview。obj 必须支持缓冲区协议。支持缓冲区协议的内置对象包括字节和字节数组。
然后我们给出示例代码:
>>> v = memoryview(b'abcefg')
>>> v[1]
98
>>> v[-1]
103
>>> v[1:4]
<memory at 0x7f3ddc9f4350>
>>> bytes(v[1:4])
b'bce'
报价结束,现在让我们仔细看看:
>>> b = b'long bytes stream'
>>> b.startswith(b'long')
True
>>> v = memoryview(b)
>>> vsub = v[5:]
>>> vsub.startswith(b'bytes')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'memoryview' object has no attribute 'startswith'
>>> bytes(vsub).startswith(b'bytes')
True
>>>
所以我从上面收集到的信息:
我们创建一个 memoryview 对象来公开缓冲区对象的内部数据而不进行复制,但是,为了对对象做任何有用的事情(通过调用对象提供的方法),我们必须创建一个副本!
当我们有一个大对象时,通常需要 memoryview(或旧的缓冲区对象),并且切片也可能很大。如果我们制作大切片,或者制作小切片但次数很多,则需要更高的效率。
使用上述方案,我看不出它对这两种情况有何用处,除非有人可以向我解释我在这里缺少什么。
编辑1:
我们有一大块数据,我们希望通过从头到尾遍历它来处理它,例如从字符串缓冲区的开头提取令牌,直到缓冲区被消耗。在 C 术语中,这是通过指针推进缓冲区,并且指针可以传递给任何期望缓冲区类型的函数。如何在 python 中完成类似的事情?
人们建议解决方法,例如许多字符串和正则表达式函数采用可用于模拟推进指针的位置参数。这有两个问题:首先它是一种变通方法,你不得不改变你的编码风格来克服这些缺点,其次:不是所有的函数都有位置参数,例如正则表达式函数和startswith
做encode()
/decode()
不做。
其他人可能会建议以块的形式加载数据,或者以大于最大令牌的小段处理缓冲区。好的,所以我们知道这些可能的解决方法,但是我们应该在 python 中以更自然的方式工作,而不是试图改变编码风格以适应语言 - 不是吗?
编辑2:
代码示例会使事情更清楚。这就是我想要做的事情,而且我认为 memoryview 乍一看会让我做的事情。让我们使用 pmview(正确的内存视图)来实现我正在寻找的功能:
tokens = []
xlarge_str = get_string()
xlarge_str_view = pmview(xlarge_str)
while True:
token = get_token(xlarge_str_view)
if token:
xlarge_str_view = xlarge_str_view.vslice(len(token))
# vslice: view slice: default stop paramter at end of buffer
tokens.append(token)
else:
break