python中交换字节的有效方法

2024-10-05 11:45:42 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一些长度为2*nbytearray

a1 a2 b1 b2 c1 c2

我需要在每个2字节的单词中切换字节endian,并使:

a2 a1 b2 b1 c2 c1

现在我使用了下一种方法,但它对我的任务来说非常缓慢:

converted = bytearray([])
for i in range(int(len(chunk)/2)):
   converted += bytearray([ chunk[i*2+1], chunk[i*2] ])

是否可以通过调用某些system/libc函数来切换bytearray的endian?


好吧,多亏了大家,我给了一些建议:

import timeit

test = [
"""
converted = bytearray([])
for i in range(int(len(chunk)/2)):
   converted += bytearray([ chunk[i*2+1], chunk[i*2] ])
""",
"""
for i in range(0, len(chunk), 2):
    chunk[i], chunk[i+1] = chunk[i+1], chunk[i]
""",
"""
byteswapped = bytearray([0]) * len(chunk)
byteswapped[0::2] = chunk[1::2]
byteswapped[1::2] = chunk[0::2]
""",
"""
chunk[0::2], chunk[1::2] = chunk[1::2], chunk[0::2]
"""
]

for t in test:
    print(timeit.timeit(t, setup='chunk = bytearray([1]*10)'))

结果是:

$ python ti.py
11.6219761372
2.61883187294
3.47194099426
1.66421198845

所以在速度片分配中,现在2步是最快的。也感谢F先生的详细解释,但我还没有尝试,因为numpy


Tags: ina2forlena1rangeb2b1
3条回答

可以使用slice赋值,步骤为2:

byteswapped = bytearray(len(original))
byteswapped[0::2] = original[1::2]
byteswapped[1::2] = original[0::2]

或者如果你想在适当的地方做:

original[0::2], original[1::2] = original[1::2], original[0::2]

计时显示,对于大型数组,切片的性能大大优于Python级别的循环:

>>> timeit.timeit('''
... for i in range(0, len(chunk), 2):
...     chunk[i], chunk[i+1] = chunk[i+1], chunk[i]''',
... 'chunk=bytearray(1000)')
81.70195105159564
>>>
>>> timeit.timeit('''
... byteswapped = bytearray(len(original))
... byteswapped[0::2] = original[1::2]
... byteswapped[1::2] = original[0::2]''',
... 'original=bytearray(1000)')
2.1136113323948393
>>>
>>> timeit.timeit('chunk[0::2], chunk[1::2] = chunk[1::2], chunk[0::2]', 'chunk=
bytearray(1000)')
1.79349659994989

对于小数组,切片仍然优于显式循环,但差别并不大:

>>> timeit.timeit('''
... for i in range(0, len(chunk), 2):
...     chunk[i], chunk[i+1] = chunk[i+1], chunk[i]''',
... 'chunk=bytearray(10)')
1.2503637694328518
>>>
>>> timeit.timeit('''
... byteswapped = bytearray(len(original))
... byteswapped[0::2] = original[1::2]
... byteswapped[1::2] = original[0::2]''',
... 'original=bytearray(10)')
0.8973060929306484
>>>
>>> timeit.timeit('chunk[0::2], chunk[1::2] = chunk[1::2], chunk[0::2]', 'chunk=
bytearray(10)')
0.6282232971918802

如果使用numpy的frombuffer函数,则可以构造一个实际共享bytearray物理内存的numpy ndarray,然后交换操作可以就地执行,而不是在副本中执行。

您可以直接在byt上执行相同的索引,例如

byt[i] = byt[i+1]

但是,在numpy中使用显式类型获得缓冲数组的句柄通常会让您做更多的事情,特别是使用bytearray,它本身非常有限。

不过要小心。尽管在Python级别,bytearray表示无符号的8位整数值(0-255),但实际的底层C实现在bytearrayobject.h中使用纯的char作为字节值(see here for more info)。如果对此使用numpy,则可能需要使用dtype=numpy.ubyte指定frombuffer的可选dtype参数。

import numpy as np
byt = bytearray(range(256))
npbyt = np.frombuffer(byt, dtype=np.ubyte)

for i in range(0, len(npbyt)-1, 2):
    temp = npbyt[i]
    npbyt[i] = npbyt[i+1]
    npbyt[i+1] = temp

print(list(byt))

它印出来了

[1, 
 0,
 3,
 2,
 5,
 4,
 ...
 255,
 254] 

我在处理一个名为buffersort的小型项目时遇到了其中的一些问题,该项目可以对实现可写缓冲区协议的Python对象执行就地排序,就像bytearray那样。

如果您对从那里获取Cython源代码感兴趣,那么有一个简单的helper函数_swap,它可以让您轻松地完成您想要的任务。不过,对于您的用例来说,这可能是非常过分的。

也可以将它们交换到适当的位置并使用原始数组。

chunk = bytearray([1,2,3,4])

for i in range(0, len(chunk), 2):
    chunk[i], chunk[i+1] = chunk[i+1], chunk[i]

相关问题 更多 >

    热门问题