Today I will go over four methods to generate a random hex string in Python.

- Firstly, from Python’s
`secrets`

module, we will use the function`token_hex(n)`

, where`n`

specifies the number of bytes. The resulting hex string will be of length`n * 2`

. - Next, we will look at another function within the
`secrets`

module –`choice()`

– and apply Python list comprehension. - But if security isn’t a concern, then feel free to use
`choice()`

from the`random`

module. - Lastly, we will explore Python’s string formatting to convert an integer to a hexadecimal string. Things to note are the preferred f-strings method over the
`str.format()`

and old %-formatting.

As you go over this tutorial, feel free to watch my explainer video:

Table of Contents

## Introduction

If you’re already familiar with hexadecimal numbers and just want to know how to generate a random hex string, then feel free to skip this introduction.

As you may know, there are various ways to represent a numbering system. Traditionally we are accustomed to the decimal (base 10) system utilizing the symbols 0 to 9.

Because of the electronic nature of computing, bits and bytes are represented with the binary (base 2) system using the symbols 0 and 1.

The hexadecimal numbering system uses 16 symbols to represent numbers. These are 0 to 9 followed by the letters a to f. Referring to the chart below, we can see decimal numbers along with their corresponding binary and hexadecimal equivalents.

Decimal | Binary | Hexadecimal |

0 | 0000 | 0 |

1 | 0001 | 1 |

2 | 0010 | 2 |

3 | 0011 | 3 |

4 | 0100 | 4 |

5 | 0101 | 5 |

6 | 0110 | 6 |

7 | 0111 | 7 |

8 | 1000 | 8 |

9 | 1001 | 9 |

10 | 1010 | a |

11 | 1011 | b |

12 | 1100 | c |

13 | 1101 | d |

14 | 1110 | e |

15 | 1111 | f |

A common implementation of hexadecimal numbers is * binary encoding*. This allows binary numbers to be a bit more readable, and also to save space. Each number in the binary column in the chart is displayed as a 4-bit value. So to represent a full byte (8 bits), we would simply use a 2-digit hexadecimal number.

Therefore, if all 8 bits are “on”: 11111111, we get “f” for the first 4 bits and another “f” for the last 4 bits resulting in ff.

In decimal, this is the number 255.

1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | |

2**7 + | 2**6 + | 2**5 + | 2**4 + | 2**3 + | 2**2 + | 2**1 + | 2**0 | = 255 |

Other common uses for hexadecimal numbers:

**HTML/CSS colors** – here’s a screenshot of the Finxter App website.

When inspecting the `“OK”`

button, we can see the hex digits that represent the color for the “`Answer Button`

” is `#48eaa9`

.

**In IPv6 representation** – the following is a brief description from Wikipedia.

*An IPv6 address is represented as eight groups of four hexadecimal digits, each group representing 16 bits. The groups are separated by colons (:). An example of an IPv6 address is:*

*2001:0db8:85a3:0000:0000:8a2e:0370:7334*

MAC addresses – This website can be used to find vendor information on a MAC address.

The above screenshot of the webpage shows an illustration of network devices and their corresponding MAC address, which is represented as hexadecimal digits delimited by colons. Here’s an explanation if you don’t know what a MAC address is.

Now that we have a general idea of hexadecimal numbers, let’s say you’re tasked with writing Python code to generate a random hex string. What’s the best way to solve this in Python?

## Method 1: secrets.token_hex()

If security or cryptography is of concern to you, then the recommended method is to utilize Python’s “`secrets`

” module. This is available in Python 3.6 and higher. We can use the built-in function `token_hex(n)`

, where `n`

specifies the number of bytes. So, if we passed in the number 1, we would get a hexadecimal string with 2 characters – 1 hex digit for each of the 4 bits.

>>> import secrets >>> secrets.token_hex(1) 'df' >>> secrets.token_hex(1) 'a0' >>> secrets.token_hex(1) 'f4' >>> secrets.token_hex(1) 'c1'

If you require a random hex string with 32 characters, then pass in the number 16 to specify 16 bytes:

>>> secrets.token_hex(16) '87ab0a3db51d297d3d1cf2d4dcdcb71b' >>> secrets.token_hex(16) '20843ab66ef431dede20cecf8d915339' >>> secrets.token_hex(16) '8d5fe6be465a5c5889e20b64fab74360' >>>

Please note the length of the hex string is equal to `n*2`

, and will therefore be an even number. For the above example, we can use slicing to obtain a hex string with 31 characters by returning the value starting from the second character:

>>> secrets.token_hex(16)[1:] 'b203a6bb0a49b95c262b13dcfaa386f' >>>

## Method 2: secrets.choice() + list comprehension

Another method from the secrets module is the `choice()`

function, which will randomly select from a sequence. Let the sequence be defined as a variable called “`hex_string`

” to hold the characters 0 to 9 and a to f.

>>> import secrets >>> hex_string = '0123456789abcdef' >>> >>> ''.join([secrets.choice(hex_string) for x in range(32)]) '66702d00f5b3b193538ed0ad181db701' >>>

As shown above, the code uses list comprehension to generate a character 32 times from the variable “`hex_string`

”. And finally using the string method `str.join()`

to concatenate the list of characters into one string.

## Method 3: random.choice() + list comprehension

If security is not a concern to you, feel free to use the `choice()`

function from Python’s `random`

module. The implementation is the same!

>>> import random >>> hex_string = '0123456789abcdef' >>> ''.join([random.choice(hex_string) for x in range(32)]) '44ab9e87c4590abf3a96dcf0b9910a49' >>>

## Method 4: Python f-Strings

For this next method, we will make use of Python’s String Formatting which has the capability of displaying integers as a string in another number system like binary, octal, or hexadecimal. As an example let’s first use f-strings and convert the number 11 to a hexadecimal string:

>>> f'{11:x}' 'b' >>>

As we can see within the curly braces, we specify the integer to convert (11), and the “`x`

” indicates that it should be converted to hexadecimal. Executing the command results in the hexadecimal string `'b'`

.

Now we’ll see how to pass in a random number with varying lengths. We will use `randrange(max)`

from the `random`

module, where the result will be greater than or equal to 0 and less than max.

Base | Power | Result | Range | Hex Max |

16 | 1 | 16 | 0 to 15 | f |

16 | 2 | 256 | 0 to 255 | ff |

16 | 3 | 4096 | 0 to 4095 | fff |

16 | 4 | 65536 | 0 to 65535 | ffff |

16 | 5 | 1048576 | 0 to 1048575 | fffff |

16 | 6 | 16777216 | 0 to 16777215 | ffffff |

16 | 7 | 268435456 | 0 to 268435455 | fffffff |

16 | 8 | 4294967296 | 0 to 4294967295 | ffffffff |

16 | 9 | 68719476736 | 0 to 68719476735 | fffffffff |

16 | 10 | 1099511627776 | 0 to 1099511627775 | ffffffffff |

Referring to the above chart, we can use the **Power** column to indicate the maximum number of digits we will require for our hexadecimal result. Since we’re focused on hexadecimal numbers, we will use base 16. Therefore, to generate a random hexadecimal number of length 1, we need to specify the max as `16**1`

. This will create a random number between 0 and 15.

>>> max = random.randrange(16**1) >>> max 15

And converting it to hexadecimal, it will always be 1 character in length since the largest possible number generated is 15 which is hex `‘f’`

.

>>> f'{max:x}' 'f'

Let’s run the code with powers from 1 to 5 to get an idea of its results. Again, we intend to generate a hex number with a length equivalent to the power.

>>> f'{random.randrange(16**1):x}' 'd' >>> f'{random.randrange(16**2):x}' 'fd' >>> f'{random.randrange(16**3):x}' '723' >>> f'{random.randrange(16**4):x}' '36cc' >>> f'{random.randrange(16**5):x}' '8490' >>>

Note on the last line, we specified the power of 5 but the result only has 4 characters. One way to fix this is to use Python’s format specifiers. Here’s the code:

>>> f'{random.randrange(16**5):05x}' '0386e' >>> f'{random.randrange(16**5):05x}' '2d9c2' >>> f'{random.randrange(16**5):05x}' '034e1' >>>

I ran it a few times to get a 4 character result. Notice, before the `x`

we have a leading zero followed by the width — 5 in this case.

For a 32 character hex string:

>>> f'{random.randrange(16**32):032x}' '029b7a391832051bdee223e7b2dc4c16' >>> f'{random.randrange(16**32):032x}' '090cb931fec129b586ef5e430b05a456' >>> f'{random.randrange(16**32):032x}' '6def4460202739d98cc7667f02a60060' >>>

Before finishing up with this method of using f-strings, I’ll mention the fact that there are 2 other ways within format specifiers to achieve the same results. The first one is with `str.format()`

. An example format for our purpose would be:

`{index:leading_zero width conversion_type}.format(index 1, index 2, … )`

Our above code can be written as follows:

>>> '{0:032x}'.format(random.randrange(16**32)) '03b2901b073ecdc38de9c69229c10ecc' >>>

And the second one (as per the Python docs, it’s called the old %-formatting):

>>> '%032x' % random.randrange(16**32) 'e32b3b9f1e649b392f6e3b4ca02f0c2b' >>>

## Conclusion

To generate a random hex string in Python, use one of the two functions from the `secrets`

module – `token_hex(n)`

or `choice()`

– if security is a concern.

Otherwise, you can use the `choice()`

function from the `random`

module.

Another elegant solution is to use Python’s string formatting methods. You may already be familiar with the old %-formatting, or the `str.format()`

methods. However, we tend to favor the f-strings method and hope you consider implementing it in your own code.

If you have any questions, then I invite you to join us on Discord (members only) to discuss this or any other topic in Python.

I hope you found this article to be interesting and helpful. I certainly enjoyed writing it, and I look forward to writing the next one!