在Python中避免不必要的切片复制

时间:2010-02-24 17:44:17

标签: python optimization idioms

对于这样的情况,是否存在避免无意义切片复制的常用习惯用法:

>>> a = bytearray(b'hello')
>>> b = bytearray(b'goodbye, cruel world.')
>>> a.extend(b[14:20])
>>> a
bytearray(b'hello world')

在我看来,创建b[14:20]切片时会发生不必要的复制。而不是在内存中创建一个新切片以提供给extend我想说“只使用当前对象的这个范围”。

某些方法可以帮助您使用切片参数,例如count

>>> a = bytearray(1000000)       # a million zero bytes
>>> a[0:900000].count(b'\x00')   # expensive temporary slice
900000
>>> a.count(b'\x00', 0, 900000)  # helpful start and end parameters
900000

但很多,例如我的第一个例子中的extend,没有此功能。

我意识到,对于许多应用程序而言,我所说的将是微优化,所以在任何人问之前 - 是的,我已经描述了我的应用程序,这是值得我担心的事情。

我在下面有一个“解决方案”,但欢迎任何更好的想法。

2 个答案:

答案 0 :(得分:5)

创建buffer对象可以避免复制切片,但对于短切片,只需复制该文件就可以了:

>>> a.extend(buffer(b, 14, 6))
>>> a
bytearray(b'hello world')

这里只有一个由内存组成的副本,但是创建buffer对象的成本超过了省略。不过对于较大的切片应该更好。我不确定这种方法的整体效率有多大。

请注意,对于Python 3(以及可选的Python 2.7),您需要一个memoryview对象:

>>> a.extend(memoryview(b)[14:20])

答案 1 :(得分:2)

itertoolsislice。 islice没有count方法,所以在你希望避免复制切片的其他情况下它很有用。正如你所指出的那样 - 无论如何,count都有一种机制

>>> from itertools import islice
>>> a = bytearray(1000000)
>>> sum(1 for x in islice(a,0,900000) if x==0)
900000
>>> len(filter(b'\x00'.__eq__,islice(a,0,900000)))
900000

>>> a=bytearray(b"hello")
>>> b = bytearray(b'goodbye, cruel world.')
>>> a.extend(islice(b,14,20))
>>> a
bytearray(b'hello world')