Explain Codes LogoExplain Codes Logo

Why does "bytes(n)" create a length n byte string instead of converting n to a binary representation?

python
byte-literals
byte-sequences
python-versions
Anton ShumikhinbyAnton Shumikhin·Dec 15, 2024
TLDR

Behold: bytes(n) simply populates a bytes object with n valorous zero bytes, not the binary shadow of n. Looking for binary? bin(n)[2:] is your friend that strips off the '0b' superhero cape. For converting n to bytes, n.to_bytes(length, 'little') rides to the rescue; length should be set to make room for n.

binary_n = bin(n)[2:] # '101' for n=5, whispers 'binary. revealed!' bytes_n = n.to_bytes(1, 'little') # b'\x05', punches in 'I'm the byte form!'
n = 5 print(binary_n) # Output: '101', secretly winking print(bytes_n) # Output: b'\x05', standing tall and proud

Converting int to bytes: Let's Get Binary!

Pause. Before we dive deeper, let's understand: int.to_bytes() is your lasso of truth for reining in binary forms of integers:

# Unsigned integers: now you see 'em, now you bytes 'em! unsigned_int = 1024 bytes_unsigned = unsigned_int.to_bytes((unsigned_int.bit_length() + 7) // 8, 'big')
# Signed integers: capture 'em in bytes, signed and sealed! signed_int = -1024 bytes_signed = signed_int.to_bytes((8 + (signed_int + (signed_int < 0)).bit_length()) // 8, 'big', signed=True) print(bytes_unsigned) # Output: b'\x04\x00', claiming 'I am the byted one!' print(bytes_signed) # Output: b'\\xfc\\x00', declaring 'Negative or not, here I byte!'

To decode these bytes back into int, int.from_bytes() does the unbiting:

print(int.from_bytes(bytes_unsigned, 'big')) # Output: 1024, saying 'Back to base!' print(int.from_bytes(bytes_signed, 'big', signed=True)) # Output: -1024, exclaiming 'Double back to base!'

For the minimalists among us who crave compact data, the struct module got your back, handling both endianess and packing formats.

The "n" in bytes(n): more than just a placeholder

bytes(n) is a like a superhero's utility belt holding n zero bytes. In the world of Python's memory allocation, bytes is a sequence type, akin to the noble lists or the ever-popular strings. It's designed for wrangling raw binary data. If you seek a bytes object encapsulating a single byte valued n, call bytes([n]) to service:

n = 65 single_byte = bytes([n]) # b'A', the lone ranger byte

What's in a byte? Literals, sequences, and you

Byte literals: True identities revealed

In Python's byte party, everyone's a character. Take b'3', b'\x33', or `b'\x03': They each encode different byte values:

  • b'3' is the heart and soul of the ASCII character '3'.
  • b'\x33' stands for hexadecimal 33, which too is ASCII '3'.
  • `b'\x03' translates to control character ETX (End of Text), not related to the digit 3. Learning these beguiling characters is crucial to tame the byte-y beast!

Crafting byte sequences: Dragon Bytes Z style!

To birth a special sequence of bytes, conjure something like:

#create your sequence, add a dose of magic desired_sequence = bytes(str(n), 'ascii') + b'\r\n' # Network protocols go 'ka-ching!'

Or to precisely control byte values in a sequence:

sequence_of_values = bytes([51, 13, 10]) # 51, 13, 10, assemble! Byte Power Rangers!

Interpolation and compatibility: Blast from the past

For those who bend time and code in Python versions 3.5 and beyond, %-interpolation for bytes and bytearray is an artefact at your disposal.

Calling all Pythoneers fighting the good fight in earlier versions: wield encoding methods to tame your dragons. Travel fearlessly between Python 2 and 3 using the reliable sidekick struct module. Time travel is tough, but Python's got your back!