42

The shortest ways I have found are:

n = 5

# Python 2.
s = str(n)
i = int(s)

# Python 3.
s = bytes(str(n), "ascii")
i = int(s)

I am particularly concerned with two factors: readability and portability. The second method, for Python 3, is ugly. However, I think it may be backwards compatible.

Is there a shorter, cleaner way that I have missed? I currently make a lambda expression to fix it with a new function, but maybe that's unnecessary.

Augustin
  • 2,444
  • 23
  • 24
geometrian
  • 14,775
  • 10
  • 56
  • 132
  • 1
    `bytes(str(n),"ascii")` is not backwards compatible, `bytes()` was introduced in python 3.x only. – Ashwini Chaudhary Dec 26 '12 at 17:31
  • I realize that you are trying to be broad to keep it from being to specific, but it's hard to tell why you're trying to do this or what exactly you're trying to achieve. – Tyler Crompton Dec 26 '12 at 17:31
  • @AshwiniChaudhary, I tried it at http://www.trypython.org/#, because my current Python is 3.3, but I acknowledge that that's hardly conclusive. – geometrian Dec 26 '12 at 17:40
  • 1
    When `bytes` exists in 2, it's only an alias for `str`. `bytearray` exists, though, and has a `bytearray(string, encoding[, errors]) -> bytearray` call signature. – DSM Dec 26 '12 at 17:45
  • @TylerCrompton, I first ran into it while porting some of my earlier code that builds packets for a custom networking layer--so it does need to use bytearrays. It was something I wasn't clear on, so I generalized it into a question. – geometrian Dec 26 '12 at 17:45
  • I don't think you have a choice in Python 3 but to use a two-step conversion, since strings and bytes are different types. But you can leave the encoding parameter off as the default will always be sufficient. – Mark Ransom Dec 26 '12 at 17:56
  • I take it back, it appears the default for the encoding parameter is a recent addition - it doesn't work at ideone.com which uses Python 3.1.2. – Mark Ransom Dec 26 '12 at 18:07
  • Why do you want the text representation? Don't networks usually use raw bytes? – Ignacio Vazquez-Abrams Dec 26 '12 at 18:32
  • @IgnacioVazquez-Abrams: exactly. It seems awkward to convert to unicode and then _back_ into a raw bytes object. – geometrian Dec 26 '12 at 19:20
  • 1
    I think what @IgnacioVazquez-Abrams meant was that a network protocol would be more likely to want binary `0x05` rather than ASCII `'5'`, but I know there are plenty of protocols that are text based. As for the double conversion to Unicode then raw bytes, it's eminently sensible when you've experienced the alternative. In Python 2 it's far too easy to get confused about whether you have a string of characters or a string of bytes and it leads to no end of bugs. – Mark Ransom Dec 26 '12 at 19:40

7 Answers7

47

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()

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'
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 4
    This doesn't work for me. str(0x04).encode() gives me '4'. I expect b'\x04'. – Tolli Feb 16 '15 at 23:44
  • 3
    @Tolli then you misunderstood the question. The goal was to produce a byte string that represents the numeric value, not the character. I think you're looking for `chr(n)`. – Mark Ransom Feb 16 '15 at 23:59
  • Ok. From the example in the question, it looks like you are right. Reading just the question, it's not coat exactly what is being asked. I actually don't want `chr(n)`, because my number may be greater than 255. The struct.pack answer below is what I wanted. – Tolli Feb 18 '15 at 00:52
  • The problem is that google searching sends you here when you are solving int to bytes, hence why I answered this question (I was trying to do what Tolli was doing). IMO These answers can easily co-exist here. Apparently [all answers were downvoted](http://stackoverflow.com/posts/14043886/timeline) which I think was unnecessary - they're all helpful. – Andy Hayden Feb 18 '15 at 01:11
  • The `.encode()` call here is effectively a no-op in Python 2, since the `str` type is already a bytes (not character text) type. But the answer still works fine. – Carl Meyer Jul 07 '16 at 16:08
  • Perfect! It is useful for create custom integers, like int8 or int16 and represent then using "bytes" class. – charles Feb 14 '22 at 13:18
38

You can use the struct's pack:

In [11]: struct.pack(">I", 1)
Out[11]: '\x00\x00\x00\x01'

The ">" is the byte-order (big-endian) and the "I" is the format character. So you can be specific if you want to do something else:

In [12]: struct.pack("<H", 1)
Out[12]: '\x01\x00'

In [13]: struct.pack("B", 1)
Out[13]: '\x01'

This works the same on both python 2 and python 3.

Note: the inverse operation (bytes to int) can be done with unpack.

Andy Hayden
  • 359,921
  • 101
  • 625
  • 535
  • This is a perfectly good answer to a very different question than the one asked here. The number 1 should yield the bytestring b'1', not b'\x01' and not related to any byte order. – Rasmus Kaj May 22 '23 at 14:18
15

I have found the only reliable, portable method to be

bytes(bytearray([n]))

Just bytes([n]) does not work in python 2. Taking the scenic route through bytearray seems like the only reasonable solution.

alex.forencich
  • 1,355
  • 11
  • 16
  • This works only for integers from 0 to 255. –  Feb 19 '23 at 12:57
  • This is a perfectly good answer to a very different question than the one asked here. bytes(bytearray([65])) is b'A', the thing requested here is b'65'. – Rasmus Kaj May 22 '23 at 14:14
9

Converting an int to a byte in Python 3:

    n = 5    
    bytes( [n] )

>>> b'\x05'

;) guess that'll be better than messing around with strings

source: http://docs.python.org/3/library/stdtypes.html#binaryseq

masad
  • 1,547
  • 1
  • 18
  • 40
Nadu
  • 2,401
  • 1
  • 25
  • 30
  • 1
    Nadu, I much prefer your answer: Comparing this answer with the one from @MarkRansom, the values returned are different: `print(str(8).encode()) #Prints b'8'` but `print(bytes([8]))` prints `b'\x08'` – Startec Aug 25 '14 at 23:48
  • @Startec indeed there is a difference: Try type( print(bytes([8])) ) and you get while the same on ....encode() give you . First is a class and later a primitive. Both are functional identical. However in some situations only one of these may be accepted. Not yet encountered that in python. But recently I had struggle in C# with int and Integer. Only the later you can use in generics. Functions demanding 'primitive' int won't accept Integer. Convert int into Integer is 'costly'. So these are like two paths you can go either the primitive or the class one. – Nadu Dec 14 '15 at 12:17
  • That could cause you a problem if your "int" is greater than 255, because of course "bytes" would expect items smaller than one byte in its initialization list. – Gustavo Meira Aug 08 '17 at 10:45
  • `bytes( [256] )` -> `ValueError: bytes must be in range(0, 256)`. Limited to small integers. – pds Feb 09 '23 at 15:46
  • Depends. If the expeted value is b'5' this is just plain wrong. So good code in some cases, but NOT an answer to this question. – Rasmus Kaj May 22 '23 at 14:13
8

In Python 3.x, you can convert an integer value (including large ones, which the other answers don't allow for) into a series of bytes like this:

import math

x = 0x1234
number_of_bytes = int(math.ceil(x.bit_length() / 8))

x_bytes = x.to_bytes(number_of_bytes, byteorder='big')

x_int = int.from_bytes(x_bytes, byteorder='big')
x == x_int
retsigam
  • 540
  • 1
  • 5
  • 13
6

from int to byte:

bytes_string = int_v.to_bytes( lenth, endian )

where the lenth is 1/2/3/4...., and endian could be 'big' or 'little'

form bytes to int:

data_list = list( bytes );
Sunber
  • 69
  • 1
  • 1
  • This does something entirely different. It converts the a number to bytes representing that number in a raw integer value, to the bytestring (e.g. (65).to_bytes()) is b'A', not b'65' as requested in the question). – Rasmus Kaj May 22 '23 at 14:11
  • moreover ` list( bytes )` does not produce an `int` but a `list` – am70 Jun 01 '23 at 20:37
1

When converting from old code from python 2 you often have "%s" % number this can be converted to b"%d" % number (b"%s" % number does not work) for python 3. The format b"%d" % number is in addition another clean way to convert int to a binary string.

b"%d" % number
user6830669
  • 161
  • 4