查看关于memoryview的文档:
memoryview对象允许Python代码在不复制的情况下访问支持缓冲区协议的对象的内部数据。
class memoryview(obj)
创建一个引用obj的memoryview。 obj必须支持缓冲区协议。 支持缓冲区协议的内置对象包括bytes和bytearray。
然后我们有以下示例代码:
>>> 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(proper memory view)来表示我正在寻找的功能:
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