2

当创建一个 Python 字节数组(传递一个整数)时,它会创建一个包含那么多字节的字节数组,并将它们全部设置为零。

我想清除字节数组,它可能非常大,迭代它并将内容设置为零这样是很差的。

有没有更好的办法?

(memoryviews 和 bytearrays 在 IMO 中的记录很差)

迄今为止最好的资源(但没有一个能回答我的问题)

http://docs.python.org/dev/library/stdtypes.html#bytes-methods

http://docs.python.org/dev/library/functions.html#bytearray

4

4 回答 4

5

为什么你会假设重新分配字节数组如此缓慢?它比使用translate或大字节数组快 10 倍以上!

我正在删除原始字节数组,因此您不必担心暂时使用双倍内存

# For small bytearray reallocation is a tiny bit faster

$ python -m timeit -s "s=bytearray('Hello World')" "s.translate('\0'*256)"
1000000 loops, best of 3: 0.672 usec per loop
$ python -m timeit -s "s=bytearray('Hello World')" "lens=len(s);del s;s=bytearray(lens)"
1000000 loops, best of 3: 0.522 usec per loop


# For large bytearray reallocation is much faster

$ python -m timeit -s "s=bytearray('Hello World'*10000)" "s.translate('\0'*256)"
1000 loops, best of 3: 225 usec per loop
$ python -m timeit -s "s=bytearray('Hello World'*10000)" "lens=len(s);del s;s=bytearray(lens)"
10000 loops, best of 3: 18.5 usec per loop

有一种更好的方法可以s保持相同的参考。您只需要调用__init__实例上的方法。

>>> s=bytearray(b"hello world")
>>> id(s)
3074325152L
>>> s.__init__(len(s))
>>> s
bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
>>> id(s)
3074325152L

测试时间

$ python -m timeit -s "s=bytearray('Hello World'*10000)" "s.__init__(len(s))"
100000 loops, best of 3: 18.7 usec per loop

我在另一台具有更多 RAM 的计算机上运行了这些千兆字节测试

$ python -m timeit -s "s=bytearray('HelloWorld'*100000000)" "s.__init__(len(s))"
10 loops, best of 3: 454 msec per loop
$ python -m timeit -s "s=bytearray('HelloWorld'*100000000)" "s.translate('\0'*256)"
10 loops, best of 3: 1.43 sec per loop
于 2013-10-30T00:00:40.697 回答
2

编辑:这个答案是错误的。s = s.translate('\0'*256)比 慢s = bytearray(256),所以在这里使用没有意义translate。@gnibbler 提供了更好的解决方案


字节数组有许多与字符串相同的方法。您可以使用翻译方法:

In [64]: s = bytearray('Hello World')

In [65]: s
Out[65]: bytearray(b'Hello World')

In [66]: import string

In [67]: zero = string.maketrans(buffer(bytearray(range(256))),buffer(bytearray(256)))

In [68]: s.translate(zero)
Out[68]: bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')

顺便说一句,Dave Beazley 写了一篇非常有用的 bytearrays 介绍


或者,稍微修改一下millimoose的答案:

In [72]: s.translate('\0'*256)
Out[72]: bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')

In [73]: %timeit s.translate('\0'*256)
1000000 loops, best of 3: 282 ns per loop

In [74]: %timeit s.translate(bytearray(256))
1000000 loops, best of 3: 398 ns per loop
于 2013-10-29T23:43:01.993 回答
2

以下是在不更改引用的情况下清除字节数组的几种不同方法(以防其他对象引用它):

  1. 使用清除():

    >>> a=bytearray(10)
    >>> a
    bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
    >>> a.clear()
    >>> a
    bytearray(b'')
    
  2. 使用切片:

    >>> a=bytearray(10)
    >>> a[0:10] = []
    >>> a
    bytearray(b'')
    >>> a=bytearray(10)
    >>> del a[0:10]
    >>> a
    bytearray(b'')
    
  3. 使用德尔:

    >>> a=bytearray(10)
    >>> b=a
    >>> del a[0:10]
    >>> a
    bytearray(b'')
    

您可以验证如果另一个变量,例如b,references a,上述技术都不会破坏这一点。以下a通过创建一个新的字节数组来重置的技术将打破这一点:

>>> a=bytearray(10)
>>> b=a
>>> b is a
True
>>> a=bytearray(10)
>>> b is a
False

但是,以上所有内容都将数组大小更改为 0。也许您只想将所有项目设为 0,保持大小不变​​,并保持所有引用有效:

>>> a=bytearray(10)
>>> b=a
>>> b is a
True
>>> a[0:10]=bytearray(10)
>>> b is a
True

因此,使用这种技术,您可以轻松地将数组的任何子部分(实际上是任何可变容器)设为 0。

于 2013-10-30T04:57:21.663 回答
0

您需要做的就是重新声明您的字节数组

b = bytearray(LEN_OF_BYTE_ARRAY)
于 2013-10-29T23:43:01.390 回答