41

I need to send a message of bytes in Python and I need to convert an unsigned integer number to a byte array. How do you convert an integer value to an array of four bytes in Python? Like in C:

uint32_t number=100;
array[0]=(number >>24) & 0xff;
array[1]=(number >>16) & 0xff;
array[2]=(number >>8) & 0xff;
array[3]=number & 0xff;

Can someone show me how? It is strange to me at first to program without types.

perelman
  • 1,747
  • 14
  • 25
Jana
  • 529
  • 2
  • 7
  • 8

7 Answers7

45

This is kind of an old thread, but in Python 3.2+ now you can simply say:

number = 100
number.to_bytes(4, byteorder = 'big')

or byteorder = 'little' as per your needs. Documentation here.

charlie80
  • 806
  • 1
  • 7
  • 17
41

Have a look at the struct module. Probably all you need is struct.pack("I", your_int) to pack the integer in a string, and then place this string in the message. The format string "I" denotes an unsigned 32-bit integer.

If you want to unpack such a string to a tuple of for integers, you can use struct.unpack("4b", s):

>>> struct.unpack("4b", struct.pack("I", 100))
(100, 0, 0, 0)

(The example is obviously on a little-endian machine.)

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • 7
    Depending on the machine this code runs on, the host byte order is probably not what you want. Use "!I" to serialize an unsigned int to network byteorder. – dantje May 31 '11 at 12:56
18

Sven has you answer. However, byte shifting numbers (as in your question) is also possible in Python:

>>> [hex(0x12345678 >> i & 0xff) for i in (24,16,8,0)]
['0x12', '0x34', '0x56', '0x78']
Community
  • 1
  • 1
Oben Sonne
  • 9,893
  • 2
  • 40
  • 61
7

You can pretty much do the same thing:

>>> number = 100
>>> array[0] = (number>>24) & 0xff
>>> array[1] = (number>>16) & 0xff
>>> array[2] = (number>>8) & 0xff
>>> array[3] = number & 0xff

or you can do something shorter:

>>> array = [(number>>(8*i))&0xff for i in range(3,-1,-1)]
matiasg
  • 1,927
  • 2
  • 24
  • 37
7

In case anyone looks at this question sometime later ...
This statement should be equivalent to the code in the original question:

>>> tuple( struct.pack("!I", number) )
('\x00', '\x00', '\x00', 'd')

And I don't think it matters what the host byte order is.
If your integers are larger than int32, you can use "!Q" in the call to pack() for int64 (if your system supports Q).
And list() or even bytearray() will work in place of tuple().

Note, the result is a sequence of str objects (each holding a single byte), not integers. If you must have a list of integers, you can do this:

[ ord(c) for c in struct.pack("!I", number) ]
[0, 0, 0, 100]

... or this:

>>> map( ord, tuple( struct.pack("!I", number) ) )
[0, 0, 0, 100]

But using map() starts making things a bit messy.

quazar
  • 79
  • 1
  • 3
2

It can be done with ctypes as well. It's especially useful for converting floating point numbers to bytes. Example:

>>> bytes(ctypes.c_uint32(0x20))
b' \x00\x00\x00'
>>> bytes(ctypes.c_double(1))
b'\x00\x00\x00\x00\x00\x00\xf0?'
enigmaticPhysicist
  • 1,518
  • 16
  • 21
0

And for completeness: you can also use the array module:

>>> from array import array
>>> a = array('I', [100]) # note that 'I' and such are machine-dependent.
>>> a.tostring()
'\d\x00\x00\x00'
>>> a.byteswap()
>>> a.tostring()
'\x00\x00\x00\d'
Mikhail Edoshin
  • 2,639
  • 16
  • 25