python将int转换为任意数量的字节

时间:2014-05-06 08:39:44

标签: python python-2.7 struct

我正面临着着名的struct.pack的一个小角落。

情况如下:我有一个带有python的薄层包装器的dll。包装器中的一个python方法接受一个字节数组作为参数。该字节数组表示特定硬件总线上的寄存器。每条总线具有不同的寄存器宽度,通常为8,16和24位宽(在所有情况下,对齐都是相同的)。

调用此方法时,我需要将我的值(无论是什么)转换为8/16或24位的字节数组。使用struct.pack:

,使用8或16位这种转换相对容易
byteList = struct.pack( '>B', regValue )    # For 8 bits case
byteList = struct.pack( '>H', regValue )    # for 16 bits case

我现在希望能够灵活地适应所有三种情况8/16& 24位。我可以使用前两行的混合来处理这三种情况;但我发现它很难看。

我希望这会奏效:

packformat = ">{0}B".format(regSize)
byteList = struct.pack( packformat, regValue )

但事实并非如此,因为struct.pack期望有相同数量的参数。

任何想法如何(整齐地)将我的寄存器值转换为任意数量的字节?

1 个答案:

答案 0 :(得分:2)

你总是打包 unsigned 整数,只有big endian才能启动。看看打包时会发生什么:

>>> import struct
>>> struct.pack('>B', 255)
'\xff'
>>> struct.pack('>H', 255)
'\x00\xff'
>>> struct.pack('>I', 255)
'\x00\x00\x00\xff'

本质上,该值在开头用空字节填充。使用它有利于您:

>>> struct.pack('>I', 255)[-3:]
'\x00\x00\xff'
>>> struct.pack('>I', 255)[-2:]
'\x00\xff'
>>> struct.pack('>I', 255)[-1:]
'\xff'

如果你的价值太大,你现在不会得到例外,但它会极大地简化你的代码。您始终可以添加单独的验证步骤:

def packRegister(value, size):
    if value < 0 or value.bit_length() > size:
        raise ValueError("Value won't fit in register of size {} bits".format(size))
    return struct.pack('>I', value)[-(size // 8):]

演示:

>>> packRegister(255, 8)
'\xff'
>>> packRegister(1023, 16)
'\x03\xff'
>>> packRegister(324353, 24)
'\x04\xf3\x01'
>>> packRegister(324353, 8)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in packRegister
ValueError: Value won't fit in register of size 8 bits