How to Generate a Random Hex String in Python?

Rate this post

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

  1. 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
  2. Next, we will look at another function within the secrets module – choice() – and apply Python list comprehension
  3. But if security isn’t a concern, then feel free to use choice() from the random module. 
  4. 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:

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.

DecimalBinaryHexadecimal
000000
100011
200102
300113
401004
501015
601106
701117
810008
910019
101010a
111011b
121100c
131101d
141110e
151111f

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.

11111111 
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. 

BasePowerResultRangeHex Max
161160 to 15f
1622560 to 255ff
16340960 to 4095fff
164655360 to 65535ffff
16510485760 to 1048575fffff
166167772160 to 16777215ffffff
1672684354560 to 268435455fffffff
16842949672960 to 4294967295ffffffff
169687194767360 to 68719476735fffffffff
161010995116277760 to 1099511627775ffffffffff

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!