Convert Python Strings to Hexadecimal

Hexadecimal representation is a cornerstone of modern computing. From debugging network packets to storing cryptographic hashes, converting strings to hex is a task every Python developer encounters. Python provides elegant, powerful tools to perform this conversion, whether you’re working with ASCII, UTF‑8, or raw binary data.

In this guide, we’ll explore multiple ways to convert Python strings to hexadecimal, discuss encoding considerations, and provide real‑world examples using languages from around the globe. By the end, you’ll have a solid understanding of how to handle hex conversion in any Python project.

Why Convert Strings to Hexadecimal?

Before diving into code, let’s review common use cases:

Method 1: The Modern Way – str.encode().hex()

Since Python 3.5, the simplest and most Pythonic way to convert a string to hexadecimal is to encode it to bytes (using your desired encoding) and then call the .hex() method on the resulting bytes object.

text = "Bonjour"
hex_string = text.encode('utf-8').hex()
print(hex_string)  # Output: 426f6e6a6f7572 

The .hex() method returns a string of lowercase hexadecimal digits, where each pair represents one byte.

Example with multiple languages:

greetings = {
    "French": "Bonjour",
    "Spanish": "Hola",
    "Italian": "Ciao",
    "German": "Guten Tag",
    "Japanese": "こんにづは",
    "Arabic": "Ù…Ű±Ű­ŰšŰ§"
}

for lang, word in greetings.items():
    hex_repr = word.encode('utf-8').hex()
    print(f"{lang}: {word} -> {hex_repr}") 

Output (truncated for clarity):

French: Bonjour -> 426f6e6a6f7572
Spanish: Hola -> 486f6c61
Italian: Ciao -> 4369616f
German: Guten Tag -> 477574656e20546167
Japanese: こんにづは -> e38193e38293e381abe381a1e381af
Arabic: Ù…Ű±Ű­ŰšŰ§ -> d985d8b1d8add8a8d8a7 

Notice that non‑ASCII characters expand to multiple bytes (e.g., こ is e3 81 93 in UTF‑8), so the hex string length is twice the number of bytes.

Method 2: Using binascii.hexlify()

Python’s binascii module provides hexlify() which does the same thing but returns a bytes object. You can then decode it to a string if needed.

import binascii

text = "MĂŒnchen"
hex_bytes = binascii.hexlify(text.encode('utf-8'))
hex_string = hex_bytes.decode('ascii')
print(hex_string)  # Output: 4dc3bcnchen 

hexlify() is particularly useful when you’re already working with bytes and want to avoid the extra encode step.

Method 3: Manual Conversion with ord() and format()

For educational purposes or when you need fine‑grained control, you can loop through each character and convert its Unicode code point to hex. However, this approach works only for strings that fit into a single‑byte encoding (like ASCII or ISO‑8859‑1). For UTF‑8, you must first encode to bytes, as shown in the previous methods.

def string_to_hex_ascii_only(text):
    return ''.join(format(ord(c), '02x') for c in text)

text = "Café"
# This works because 'Ă©' is within Latin-1, but fails for multi-byte characters
print(string_to_hex_ascii_only(text))  # Output: 436166e9 (incorrect for UTF-8) 

For correct UTF‑8 handling, always encode first:

def string_to_hex_utf8(text):
    return text.encode('utf-8').hex()

print(string_to_hex_utf8("Café"))  # Output: 436166c3a9 

Method 4: Working Directly with bytes or bytearray

If you already have a bytes object (e.g., from reading a file), you can call .hex() directly:

data = b"Hello World"
hex_repr = data.hex()
print(hex_repr)  # Output: 48656c6c6f20576f726c64 

Similarly, a bytearray also has the .hex() method.

Handling Different Encodings

The examples above use UTF‑8, the most common encoding. But you can choose any encoding your application requires. For instance, UTF‑16‑LE:

text = "ПроĐČДт"  # Russian for "Hello"
hex_utf16le = text.encode('utf-16-le').hex()
print(hex_utf16le)  # Output: 1f04410438043204350442 

If you need to convert back, use bytes.fromhex() or binascii.unhexlify():

original = bytes.fromhex(hex_utf16le).decode('utf-16-le')
print(original)  # Output: ПроĐČДт 

Converting Hexadecimal Back to String

To reverse the process, you can use bytes.fromhex() or binascii.unhexlify() and then decode the bytes.

hex_string = "48656c6c6f20576f726c64"
decoded_bytes = bytes.fromhex(hex_string)
original_text = decoded_bytes.decode('utf-8')
print(original_text)  # Output: Hello World 

If the hex string was produced with a different encoding, you must decode with the same encoding:

hex_utf8 = "e38193e38293e381abe381a1e381af"  # "こんにづは"
decoded = bytes.fromhex(hex_utf8).decode('utf-8')
print(decoded)  # Output: こんにづは 

Practical Examples

1. Storing Binary Data in JSON

When you need to store binary data (e.g., an image) in a JSON file, encode it as hex:

import json

with open('image.jpg', 'rb') as f:
    binary_data = f.read()

hex_data = binary_data.hex()

data_to_store = {
    "filename": "image.jpg",
    "content": hex_data
}

with open('metadata.json', 'w') as f:
    json.dump(data_to_store, f) 

Later, retrieve and reconstruct the binary file:

with open('metadata.json', 'r') as f:
    loaded = json.load(f)

original_binary = bytes.fromhex(loaded['content'])
with open('restored_image.jpg', 'wb') as f:
    f.write(original_binary) 

2. Generating a SHA‑256 Hash in Hex

Hashing functions often return bytes; .hex() makes them human‑readable:

import hashlib

text = "The quick brown fox jumps over the lazy dog"
hash_bytes = hashlib.sha256(text.encode('utf-8')).digest()
hash_hex = hash_bytes.hex()
print(hash_hex)
# Output: d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592 

3. URL‑safe Data Transfer

Hexadecimal strings are URL‑safe (only digits and letters A‑F). This makes them ideal for transmitting binary data in query parameters.

import urllib.parse

user_data = "user:secret"
hex_data = user_data.encode('utf-8').hex()
url = f"https://example.com/api?token={hex_data}"

# On the receiving side
received_hex = urllib.parse.parse_qs(urllib.parse.urlparse(url).query)['token'][0]
decoded = bytes.fromhex(received_hex).decode('utf-8')
print(decoded)  # Output: user:secret 

Performance Considerations

For most applications, the built‑in .hex() method is implemented in C and is extremely fast. If you’re converting huge amounts of data (e.g., multi‑gigabyte files), consider processing in chunks to avoid memory exhaustion:

def file_to_hex_chunked(filepath, chunk_size=8192):
    with open(filepath, 'rb') as f:
        while chunk := f.read(chunk_size):
            yield chunk.hex()

# Example: write hex to a file
with open('output.hex', 'w') as out:
    for hex_chunk in file_to_hex_chunked('largefile.bin'):
        out.write(hex_chunk) 

Edge Cases and Common Pitfalls

Conclusion

Converting Python strings to hexadecimal is straightforward thanks to the language’s powerful bytes and string methods. The modern approach—.encode().hex()—is concise, efficient, and works with any encoding, making it the go‑to solution for most tasks. For scenarios where you’re already dealing with bytes, .hex() on the bytes object is equally simple.

In this guide, we’ve covered:

With these tools in your Python toolkit, you’ll be able to handle hex conversions confidently in any project.