Converting integer to byte string problem in python 3

I have a library function that is failing because I cannot seem to properly convert an integer to a proper byte string except by using a literal. Can someone explain why I get 3 different results from 3 different ways to convert an integer to a byte string?

Using a literal, which is the only way the library call works produces this:

>>> print(b'1')
b'1'

Using the builtin bytes function, which the library call rejects, is really strange:

>>> i=1
>>> print(bytes(i))
b'\x00'

Finally using the to_bytes function, which the library call also rejects, is:

>>> i=1
>>> print(i.to_bytes(1,byteorder='big'))
b'\x01'

At least the value seems right. Can someone explain why only using a literal works and/or the print output is different?

Hi Gw1500se1,

Have you read the docs for bytes? You can read the full documentation
online, or you can get a summary in the interactive interpreter:

help(bytes)

You tried bytes(1) hoping to get the byte b'1' but that’s not how
bytes work. When given an int argument, it is used to give that many
null bytes:

> bytes(5)
b'\x00\x00\x00\x00\x00'
> bytes(10)
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

Likewise, the to_bytes method of ints returns bytes, but its not clear
to me whether you want the byte with numeric value 1 (or 0x01 in hex) or
the byte for the ASCII digit “1”, they are very different things:

> ord(b'\x01')  # the byte with hex value 0x01
1
> ord(b'1')  # the byte for the ASCII digit 1
49

If you want ASCII digits, then you can do this:

> n = 785
> bytes(str(n), 'ascii')
b'785'

If you want the bytes with the specified numeric values, you can do
this:

# only one numeric value
> bytes([68])
b'D'

# more than one
> bytes([68, 69, 65, 68, 32, 66, 69, 69, 70])
b'DEAD BEEF'

There I have given the values in decimal. If you prefer them in
hexadecimal, it’s a bit longer to type:

> bytes([0x44, 0x45, 0x41, 0x44, 0x20, 0x42, 0x45, 0x45, 0x46])
b'DEAD BEEF'

Alternatively, you can make one larger number, here shown in hex:

> (0x444541442042454546).to_bytes(12, 'big')
b'\x00\x00\x00DEAD BEEF'

There are other options as well, but without knowing precisely what you
are after it is hard for me to tell what will solve your problem.

1 Like

The main question is what the “proper byte string” for an integer is in the context of your library function.

However your examples do the following:

Example 1

>>> print(b'1')

Here b'1' is a byte object of length 1 containing the byte that represent the ASCII character for the digit 1. It’s value is 49 (which you can see by typing b'1'[0] in your Python shell).

Example 2

>>> i=1
>>> print(bytes(i))

Here you’re creating a new bytes object of length 1, that Python will fill with the value 0. See doc(bytes) for why this is happening:

bytes(iterable_of_ints) -> bytes
bytes(string, encoding[, errors]) -> bytes
bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer
bytes(int) -> bytes object of size given by the parameter initialized with null bytes
bytes() -> empty bytes object

Construct an immutable array of bytes from:
  - an iterable yielding integers in range(256)
  - a text string encoded using the specified encoding
  - any object implementing the buffer API.
  - an integer

Example 3

>>> i=1
>>> print(i.to_bytes(1,byteorder='big'))

Here you’re converting an integer (where more than one byte might be required to store the value) to a bytes object that contains exactly those bytes. However since your integer value is really small, it fits into one byte, and then the order of the bytes becomes irrelevant anyway.

Solution?

If I understood you correctly the output of example 1, is the correct output, which suggests that what you need is a bytes object containing the ASCII digits of the decimal representation of the integer. To get this, do the following:

>>> value = 123
>>> print(bytes(str(value), 'ascii'))
b'123'

Thanks for the replies. Yes, example 1 produces the correct input to the function. I need to study your example to understand why something so seemingly simple needs to be so complex. I never would have puzzled that out on my own. I’m mostly a PHP programmer and there it is very simple.

It’s complex because the problem has many variations. People want to do
all of these things, and Python supports them all:

  • convert a string of hex digits into bytes?

  • convert numeric values into bytes with the same numeric values?

  • convert ASCII strings into bytes?

  • convert non-ASCII Unicode strings into bytes?

It might help if you show us how you would solve this in PHP, showing
both the input you have and the output you expect.

I have it working now. PHP has a ‘pack’ function that does it.

struct.pack is similar to PHP’s pack.

>>> from struct import pack
>>> pack('b', 1)
b'\x01'

Beware that the format codes are different from PHP.

>>> pack('4bi', 1, 2, 3, 4, 65535)
b'\x01\x02\x03\x04\xff\xff\x00\x00'
1 Like