6

对于这样的情况,是否有避免无意义的切片复制的常见习语:

>>> 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我的第一个例子,没有这个功能。

我意识到对于许多应用程序来说,我所说的将是一个微优化,所以在任何人问之前 - 是的,我已经分析了我的应用程序,这对于我的情况值得担心。

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

4

2 回答 2

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])
于 2010-02-24T17:44:35.897 回答
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')
于 2010-02-24T20:49:08.693 回答