Converting Python Bytes to Hex

Introduction
Working with binary data is a daily task for many Python developers, especially when dealing with network protocols or file formats. Yet one small step that often slips under the radar is how we convert raw bytes into a readable hex string. Why does this simple conversion matter when you can just print raw bytes?
Fortunately, Python offers built-in ways to turn bytes into hex quickly and reliably. By mastering methods like bytes.hex()
or the binascii module, you can debug data flows, optimize memory use, and avoid unexpected errors.
Understanding Bytes and Hex
Before diving into code, it helps to understand what bytes and hex strings represent. A byte in Python is an immutable sequence of integers between 0 and 255. Internally, each byte holds 8 bits of data. You can create a bytes object using a constructor like:
data = bytes([104, 101, 108, 108, 111]) # b'hello'
Hexadecimal is a base-16 numbering system. It uses digits 0 to 9 and letters a to f to represent values. One hex digit represents 4 bits, so two hex digits map exactly to one byte. For example, the byte value 255 becomes ff
in hex, while 16 becomes 10
.
Representing bytes as hex strings offers clear advantages. It makes logs more readable, eases debugging when you inspect raw data, and helps when sending binary over text-based channels like JSON or HTTP. Once you see raw bytes as hex pairs, it is easier to spot patterns and errors.
Built-in Python Methods
Python provides simple built-in tools for converting bytes to hex.
data = bytes([0, 255, 16])
hex_str = data.hex()
print(hex_str) # 00ff10
The bytes.hex()
method works in Python 3.5 and later. It returns a lowercase string with two hex digits per byte. For uppercase output, you can chain a call:
hex_str_upper = data.hex().upper()
print(hex_str_upper) # 00FF10
For older versions or more control, use the binascii module:
import binascii
raw = bytes([0x1a, 0x2b, 0x3c])
hexl = binascii.hexlify(raw)
print(hexl) # b'1a2b3c'
print(hexl.decode()) # 1a2b3c
Tip: use
bytes.hex()
for simple cases. Reach forbinascii.hexlify
when you need a bytes result or work in older environments.
Both approaches are reliable. Choose based on your version, output format, and performance needs.
Converting Hex to Bytes
Often you need to reverse the process. To turn a hex string back into bytes, Python offers a straightforward method:
hex_str = 'deadbeef'
raw = bytes.fromhex(hex_str)
print(list(raw)) # [222, 173, 190, 239]
The bytes.fromhex
class method expects a string with an even number of hex digits. If you include spaces between pairs, it still works:
raw2 = bytes.fromhex('de ad be ef')
print(list(raw2)) # [222, 173, 190, 239]
Be cautious when reading hex from user input or files. Always validate the length and content:
if len(hex_str) % 2 != 0:
raise ValueError('Hex string length must be even')
Converting back and forth ensures data integrity when you encode, transmit, then decode binary content.
Performance Considerations
When handling large volumes of bytes, conversion speed can matter. Benchmark with the timeit module:
import timeit
import binascii
setup = 'data = bytes([120] * 1024)'
stmt1 = 'data.hex()'
stmt2 = 'binascii.hexlify(data)'
print(timeit.timeit(stmt1, setup=setup, number=10000))
print(timeit.timeit(stmt2, setup=setup, number=10000))
Results vary by Python version and system, but bytes.hex()
is typically optimized in C. Meanwhile, binascii.hexlify
may be faster if you avoid an extra decode call.
- Reuse data buffers where possible
- Avoid calling hex conversion in tight loops
- Profile with real-world data sizes
Performance tip: if you only need a bytes result from hexlify, skip the decode step to save cycles.
Understanding performance helps you choose the right method when processing logs, cryptographic hashes, or binary protocols.
Common Use Cases
Converting bytes to hex appears in many areas of development:
- Debugging network traffic: hex dumps reveal packet contents.
- Hashing and checksums: digest methods like SHA256 return bytes that you often display as hex.
- Data serialization: encoding binary in text formats (JSON, XML).
- File I/O: inspecting binary files before writing or after reading.
- Encoding-aware conversions: bridge to string operations like binary to string conversion.
In some workflows you may also convert hex back to ints:
value = int.from_bytes(raw, 'big')
For more on that, see the guide on bytes to int conversion.
Tips and Best Practices
To make your hex conversions robust:
- Validate inputs: check string length and character set.
- Control case: decide on upper or lower hex and stick with it.
- Add separators: use a join expression for spaced formats.
- Reuse buffers: avoid creating new objects in heavy loops.
Always log both raw and hex output in tandem when diagnosing tricky encoding issues.
By following consistent patterns, teammates can read your logs without confusion. Automated tools can then parse predictable hex formats reliably.
Conclusion
Converting bytes to hex in Python is a small but powerful skill. You can use bytes.hex()
, binascii.hexlify
, and bytes.fromhex
to inspect, log, and process data in a readable form. Understanding performance differences and common pitfalls ensures you make the right choice for your project.
Whether you are debugging network packets, generating cryptographic digests, or building data pipelines, knowing how to round-trip between bytes and hex gives you clarity and control. Try these techniques in your next script and see how much smoother your binary data tasks become.
Subscribe to my newsletter
Read articles from Mateen Kiani directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
