【问题标题】:Buffers and Memoryview Objects explained for the non-C programmer为非 C 程序员解释的缓冲区和 Memoryview 对象
【发布时间】:2011-07-18 17:25:17
【问题描述】:

Python 2.7 引入了new API for buffers and memoryview objects

我阅读了有关它们的文档,并且我认为我了解了基本概念(以原始形式访问对象的内部数据而不复制它,我认为这意味着获取对象的“更快且更少占用内存”的方式数据),但要真正理解文档,读者应该对 C 有一定的了解。

如果有人愿意花时间做以下事情,我将不胜感激:

  • 用“外行术语”解释缓冲区和 memoryview 对象,并
  • 描述一个场景,其中使用缓冲区和 memoryview 对象将是“Python 风格”的做事方式

【问题讨论】:

  • 看看this answer,它解释了它们在纯 Python 中的使用,尽管它没有进入 C API。
  • @Scott - 在我发布这个问题之前已经阅读(并赞成)。 :) 确实非常有用。 @agf 的回答(和链接!)帮助我了解更多......仍然 C-API 的事情让我有点困惑:只是为了解释创建 memoryview 类型的理由而提到的,还是我应该做些什么绝对知道吗?还有:为什么不能写暴露缓冲区接口的对象?这是 Guido & Co. 的设计选择,还是 python 内部工作的隐含限制?
  • @agf - 感谢您的评论,但我认为我的评论被误解了:我指的是@Scott 自己在评论中链接的答案。答案的最后一句话是:“还要注意,如果不深入研究 C API,就无法为自己的对象实现缓冲区接口,也就是说,你无法在纯 Python 中实现。”
  • @mac 是的,我错过了。我认为 C-API 之所以经常被提及,是因为在 Python 2.6 之前,它是使用(旧)缓冲区接口/协议的唯一方法。因此,已经熟悉 Python 中的“缓冲区”的人会这样看待它们。使用 2.6+ 缓冲区对象或 2.7+ memoryview 对象无需了解任何相关信息。然而,它确实解释了为什么缓冲区对象是只读的:因为缓冲区总是只能从 Python 编写的代码中读取,所以我们需要调用可用于 Python 代码的读写缓冲区(内存视图)。
  • 我的理解是纯 Python 类型无法实现 memoryview 接口没有根本原因,只是没有提供。我想如果你真的需要它,那么你可能正在做一些相当低级和性能关键的事情,并且已经在使用 C(或者也许应该使用它)。这不是我的经验,但无论哪种方式,我认为我们不会很快获得纯 Python 内存视图类型。

标签: python c python-2.7 python-2.x memoryview


【解决方案1】:

这是我写的哈希函数中的一行:

M = tuple(buffer(M, i, Nb) for i in range(0, len(M), Nb))

这会将长字符串 M 拆分为长度为 Nb 的较短“字符串”,其中 Nb 是我一次可以处理的字节数/字符数。它在不复制字符串的任何部分的情况下执行此操作,就像我这样对字符串进行切片时会发生的情况:

M = tuple(M[i*Nb:i*Nb+Nb] for i in range(0, len(M), Nb))

我现在可以像切片一样遍历 M:

H = key
for Mi in M:
    H = encrypt(H, Mi)

基本上,缓冲区和内存视图是处理 Python 中字符串的不变性以及切片等一般复制行为的有效方法。内存视图就像一个缓冲区,除了您还可以写入它,而不仅仅是读取。

虽然主缓冲区/memoryview 文档是关于 C 实现的,但标准类型页面在 memoryview 下有一些信息:http://docs.python.org/library/stdtypes.html#memoryview-type

编辑:在我的书签中找到了这个,http://webcache.googleusercontent.com/search?q=cache:Ago7BXl1_qUJ:mattgattis.com/2010/3/9/python-memory-views+site:mattgattis.com+python&hl=en&client=firefox-a&gl=us&strip=1 是一个非常好的简短文章。

编辑 2:原来我首先从 When should a memoryview be used? 获得了该链接,该问题从未得到详细回答,并且该链接已失效,因此希望这会有所帮助。

【讨论】:

  • 等等...你真的可以使用memoryview改变字符串(和/或其他不可变对象)吗?
  • 不——你只能改变可变对象,比如字节数组。 memoryview 有一个readonly 属性,它会告诉你是否可以。
【解决方案2】:

我一直在寻找的部分答案是 buffer 是“旧方式”,memoryview 是新方式,但已向后移植到 2.7 - 请参阅存档博客 here

这并没有回答我的问题,即为什么我认为我在 2.7 中实现的 C API 允许我构造 buffer 而不是 memoryview...

要让memoryview 在Python 2.7 中工作,您需要在tp_flags 中设置Py_TPFLAGS_HAVE_NEWBUFFER 标志。我发现内置的bytearray 源是一个很好的参考;它位于Include/bytearrayobject.hObjects/bytearrayobject.c

【讨论】:

  • 此答案中的链接已失效。
  • 我复活了链接buhahah
猜你喜欢
  • 1970-01-01
  • 2019-02-26
  • 1970-01-01
  • 2011-03-25
  • 1970-01-01
  • 2012-02-07
  • 2012-04-24
  • 1970-01-01
  • 2010-10-19
相关资源
最近更新 更多