Я не делал никаких тестов, но этот рецепт «работает для меня».
Короткая версия: используйте '%x' % val
, затем unhexlify
результат.Дьявол кроется в деталях, так как unhexlify
требует четного числа шестнадцатеричных цифр, что %x
не гарантирует.См. Подробности в документации и комментарии к нему.
from binascii import unhexlify
def long_to_bytes (val, endianness='big'):
"""
Use :ref:`string formatting` and :func:`~binascii.unhexlify` to
convert ``val``, a :func:`long`, to a byte :func:`str`.
:param long val: The value to pack
:param str endianness: The endianness of the result. ``'big'`` for
big-endian, ``'little'`` for little-endian.
If you want byte- and word-ordering to differ, you're on your own.
Using :ref:`string formatting` lets us use Python's C innards.
"""
# one (1) hex digit per four (4) bits
width = val.bit_length()
# unhexlify wants an even multiple of eight (8) bits, but we don't
# want more digits than we need (hence the ternary-ish 'or')
width += 8 - ((width % 8) or 8)
# format width specifier: four (4) bits per hex digit
fmt = '%%0%dx' % (width // 4)
# prepend zero (0) to the width, to zero-pad the output
s = unhexlify(fmt % val)
if endianness == 'little':
# see http://stackoverflow.com/a/931095/309233
s = s[::-1]
return s
... и мои тест на нос модульные тесты; -)
class TestHelpers (object):
def test_long_to_bytes_big_endian_small_even (self):
s = long_to_bytes(0x42)
assert s == '\x42'
s = long_to_bytes(0xFF)
assert s == '\xff'
def test_long_to_bytes_big_endian_small_odd (self):
s = long_to_bytes(0x1FF)
assert s == '\x01\xff'
s = long_to_bytes(0x201FF)
assert s == '\x02\x01\xff'
def test_long_to_bytes_big_endian_large_even (self):
s = long_to_bytes(0xab23456c8901234567)
assert s == '\xab\x23\x45\x6c\x89\x01\x23\x45\x67'
def test_long_to_bytes_big_endian_large_odd (self):
s = long_to_bytes(0x12345678901234567)
assert s == '\x01\x23\x45\x67\x89\x01\x23\x45\x67'
def test_long_to_bytes_little_endian_small_even (self):
s = long_to_bytes(0x42, 'little')
assert s == '\x42'
s = long_to_bytes(0xFF, 'little')
assert s == '\xff'
def test_long_to_bytes_little_endian_small_odd (self):
s = long_to_bytes(0x1FF, 'little')
assert s == '\xff\x01'
s = long_to_bytes(0x201FF, 'little')
assert s == '\xff\x01\x02'
def test_long_to_bytes_little_endian_large_even (self):
s = long_to_bytes(0xab23456c8901234567, 'little')
assert s == '\x67\x45\x23\x01\x89\x6c\x45\x23\xab'
def test_long_to_bytes_little_endian_large_odd (self):
s = long_to_bytes(0x12345678901234567, 'little')
assert s == '\x67\x45\x23\x01\x89\x67\x45\x23\x01'