Converting Int to Bytes in Python 3

Converting int to bytes in Python 3

Python 3.5+ introduces %-interpolation (printf-style formatting) for bytes:

>>> b'%d\r\n' % 3
b'3\r\n'

See PEP 0461 -- Adding % formatting to bytes and bytearray.

On earlier versions, you could use str and .encode('ascii') the result:

>>> s = '%d\r\n' % 3
>>> s.encode('ascii')
b'3\r\n'

Note: It is different from what int.to_bytes produces:

>>> n = 3
>>> n.to_bytes((n.bit_length() + 7) // 8, 'big') or b'\0'
b'\x03'
>>> b'3' == b'\x33' != b'\x03'
True

Convert int to byte in Python

Convert the int to a str then .encode into bytes:

>>> x = 123456
>>> bs = str(x).encode('ascii')
>>> bs
b'123456'

Convert n-byte int to bytes in python3

I'm guessing you need a 32-bit integer, and big-endian to boot:

>>> from ctypes import c_uint32
>>> l = c_uint32(0x12345678)
>>> bytes(l)
b'xV4\x12'

There is c_uint8, c_uint16 and c_uint64 as well. For longer ints you need to make it manually, using divmod(x, 256).

>>> def bytify(v):
... v, r = divmod(v, 256)
... yield r
... if v == 0:
... raise StopIteration
... for r in bytify(v):
... yield r
...
>>> [x for x in bytify(0x12345678)]
[120, 86, 52, 18]
>>> bytes(bytify(0x12345678))
b'xV4\x12
>>> bytes(bytify(0x123456789098765432101234567890987654321))
b'!Ce\x87\t\x89gE#\x01!Ce\x87\t\x89gE#\x01'

Python 3 Converting integers to bytes correctly:

Those two examples are not equivalent. str(n).encode() takes whatever you give it, turns it into its string representation, and then encodes using a character codec like utf8. bytes([..]) will form a bytestring with the byte values of the array given. The representation \xFF is in fact the hexadecimal representation of a single byte value.

>>> str(8).encode()
b'8'
>>> b'8' == b'\x38'
True

Python 2,3 Convert Integer to bytes Cleanly

Answer 1:

To convert a string to a sequence of bytes in either Python 2 or Python 3, you use the string's encode method. If you don't supply an encoding parameter 'ascii' is used, which will always be good enough for numeric digits.

s = str(n).encode()
  • Python 2: http://ideone.com/Y05zVY
  • Python 3: http://ideone.com/XqFyOj

In Python 2 str(n) already produces bytes; the encode will do a double conversion as this string is implicitly converted to Unicode and back again to bytes. It's unnecessary work, but it's harmless and is completely compatible with Python 3.


Answer 2:

Above is the answer to the question that was actually asked, which was to produce a string of ASCII bytes in human-readable form. But since people keep coming here trying to get the answer to a different question, I'll answer that question too. If you want to convert 10 to b'10' use the answer above, but if you want to convert 10 to b'\x0a\x00\x00\x00' then keep reading.

The struct module was specifically provided for converting between various types and their binary representation as a sequence of bytes. The conversion from a type to bytes is done with struct.pack. There's a format parameter fmt that determines which conversion it should perform. For a 4-byte integer, that would be i for signed numbers or I for unsigned numbers. For more possibilities see the format character table, and see the byte order, size, and alignment table for options when the output is more than a single byte.

import struct
s = struct.pack('<i', 5) # b'\x05\x00\x00\x00'

Convert bytes to int?

Assuming you're on at least 3.2, there's a built in for this:

int.from_bytes( bytes, byteorder, *, signed=False )

...

The argument bytes must either be a bytes-like object or an iterable
producing bytes.

The byteorder argument determines the byte order used to represent the
integer. If byteorder is "big", the most significant byte is at the
beginning of the byte array. If byteorder is "little", the most
significant byte is at the end of the byte array. To request the
native byte order of the host system, use sys.byteorder as the byte
order value.

The signed argument indicates whether two’s complement is used to
represent the integer.

## Examples:
int.from_bytes(b'\x00\x01', "big") # 1
int.from_bytes(b'\x00\x01', "little") # 256

int.from_bytes(b'\x00\x10', byteorder='little') # 4096
int.from_bytes(b'\xfc\x00', byteorder='big', signed=True) #-1024

Python: convert from INT to BYTES issue

Python represents bytes in such a way that if a value is printable ASCII, it will use that instead of an escape sequence. You can try it out:

>>> b'\x0a'
b'\n'
>>> b'\x32'
b'2'

And it checks out: \n is Python's escape sequence for newline (ASCII character 10), and 2 is ASCII character 50.

Convert back from int to byte

You can accomplish this using the int to_bytes method. Here is an example:

value = int.from_bytes(bytevalues, byteorder='big') 
new_bytevalues = value.to_bytes(length=len(bytevalues), byteorder='big')
print(new_bytevalues == bytevalues) # prints True

In to_bytes, we have to define length to be at least the size of the original bytes object. If it is not, it will cause an OverflowError. It can be bigger than the length of the original bytes object, and in that case it will just pad the result with zeros.

Python3 How to make a bytes object from a list of integers

Just call the bytes constructor.

As the docs say:

… constructor arguments are interpreted as for bytearray().

And if you follow that link:

If it is an iterable, it must be an iterable of integers in the range 0 <= x < 256, which are used as the initial contents of the array.

So:

>>> list_of_values = [55, 33, 22]
>>> bytes_of_values = bytes(list_of_values)
>>> bytes_of_values
b'7!\x16'
>>> bytes_of_values == '\x37\x21\x16'
True

Of course the values aren't going to be \x55\x33\x22, because \x means hexadecimal, and the decimal values 55, 33, 22 are the hexadecimal values 37, 21, 16. But if you had the hexadecimal values 55, 33, 22, you'd get exactly the output you want:

>>> list_of_values = [0x55, 0x33, 0x22]
>>> bytes_of_values = bytes(list_of_values)
>>> bytes_of_values == b'\x55\x33\x22'
True

Converting integers to Bytes in python

It looks like you're working on building out a IPv4 packet header (you should've mentioned this in your question, assuming you know this to be the case).

Your logic currently takes the version and appends it to your byte array as a whole byte (8 bits), but it should only occupy the first 4 bits (or 1 nibble).

You're likely expecting the first byte to be "E" because 0b0100_0101 (that is, 4 represented as 4 bits followed by 5 represented as 4 bits, as shown in the diagram below) is 69 in decimal, which is the ASCII character for "E". So, if you were to run strings or hexdump on a TCPv4 packet, you might see "E" as the first character. However, the first byte should actually be 0x45, so you're confusing the representations of the initial byte.

Sample Image

Your code isn't quite right because it's treating the version and hdrlen as two separate bytes when they should be in the same byte as two separate nibbles.

So, you want something like:

first_byte = version << 4 | length

This should give you enough direction. Best of luck.



Related Topics



Leave a reply



Submit