【问题标题】:Efficiently slicing a string in Python3在 Python3 中有效地对字符串进行切片
【发布时间】:2018-08-13 19:31:24
【问题描述】:

由于 python 执行slice-by-copy,因此对字符串进行切片可能会非常昂贵。

我有一个对字符串进行操作的递归算法。具体来说,如果向函数传递了一个字符串a,该函数会在传递的字符串的a[1:] 上调用自身。问题是字符串太长了,逐个复制机制正在成为删除第一个字符的一种非常昂贵的方法。

有没有办法解决这个问题,还是我需要完全重写算法?

【问题讨论】:

  • 你说得对,我只是误解了 memoryview 的工作原理,并认为它是一样的。结束问题。
  • 另外,a[:1] 正在切掉第一个字符(如果有的话),这非常便宜。你的意思是a[1:](它会分割所有第一个字符)?
  • 是的,我做到了。谢谢你的收获。
  • @sudo:列表切片创建新的lists;当然,不会复制 len 1 str 对象,但指向它们的指针会被复制,并且指针是 4-8 个字节,而字符串中的每个字符是 1-4 个字节。 list 切片的大 O 成本与 str 切片的成本相同。对于 Python 内置类型,只有 O(1) 切片的类型是 memoryview 和(在 Py3 上)rangenumpy 添加了一系列类似视图的序列,但它不是内置包。
  • @sudo: str 切片复制而不是部分创建视图以保持实现更简单(原始数据可以与对象头一起分配在单个块中,无需分配数据单独使用单独的引用计数,并避免将偏移量存储到数据中),并部分避免保活效应。如果有人做了类似smallstr = mystr[1:11] 之类的事情,其中​​mystr 的长度为1 GB,那么仅仅因为smallstr 正在查看其中的10 个字符而让mystr 永远存在是很荒谬的。

标签: python string slice


【解决方案1】:

解决这个问题的唯一方法是让你的算法使用bytes-like 类型,Py2 str 或 Py3 bytes;不支持 Py2 unicode/Py3 str 的视图。我在my answera related question 上提供了有关如何执行此操作的详细信息,但简短的版本是,如果您可以假设bytes 类似的参数(或转换为它们),则将参数包装在memoryview 中并切片是一个合理的解决方案。转换为 memoryview 后,切片会产生新的 memoryviews,其成本为 O(1)(时间和内存),而不是文本切片的 O(n) 时间/内存成本。

【讨论】:

  • n.b. bytes 将不起作用,除非字符串是固定长度的编码,如 ASCII。例如,utf8 不起作用,但您可以轻松转换为 utf32 来解决这个问题。
  • @sudo:是的,我的另一个答案涵盖了这个问题。这不像“转换为utf-32”那么简单; UTF-32 是固定长度的,但您要么必须放弃类似bytes 的行为(例如,在 Py3 上将 memoryview 转换为四字节格式),要么保持bytes 类似但手动调整更大的字符每次宽度(每次切掉前四个字节而不是第一个字符)。这可能是一种痛苦。
  • 谢谢,可靠的答案。我觉得很容易被 Python 中的简单操作所吸引而完全忘记它们的效率。很好奇,您是如何学习 Python 操作的所有这些大 O 保证的?
  • @lieblos:在大多数情况下,语言规范不提供保证(Python 教程提到切片 list 浅拷贝,但除此之外没有涉及)。 str slices 是副本与视图之类的东西不是语言保证;曾几何时,他们考虑制作 str 切片视图,但主要是因为隐含的、非直观的保活效果(从 1 GB str 中切出两个字符导致 1 GB str 存活直到切片被清理干净)。大多数情况下,我只是阅读 Python 错误跟踪器、PEP 和每个版本的 What's New 页面。
  • @sudo:在某种程度上,是的。对各种内置类型的要求意味着您只有几个实用选项,所有这些选项都共享相同的 big-O 性能。一些 big-Os 是偶然记录的(例如,list 具有 O(n) 左侧的 pop/insert 的内存移动成本记录为 collections.deque 的详细信息,它的存在是为了缓解这种情况问题,就像listO(1) 随机访问一样,collections.deque 缺少)。在实践中,list 总是像 C++ 一样,vectorset/dict 是基于哈希的,等等。新的解决方案并不经常发明。
猜你喜欢
  • 2012-07-13
  • 1970-01-01
  • 2014-07-08
  • 1970-01-01
  • 2012-11-20
  • 2011-12-03
  • 2021-03-14
  • 2021-03-12
  • 2014-01-22
相关资源
最近更新 更多