import random
import string

def random_char(y):
    return ''.join(random.choice(string.ascii_uppercase) for x in range(y))

p1 = str(random.randrange(1, 99))
p2 = str(random_char(5))
p3 = str(random.randrange(1, 9))
p4 = str(random_char(2))
p5 = str(random.randrange(1, 9))
p6 = str(random_char(1))  # Y
p7 = str(random.randrange(1, 9))  # 7
p8 = str(random_char(3))  # AUS
result = p1 + p2+p3+p4+p5+p6+p7+p8

I generate a specific code like "31SPZVG2CZ2R8WFU" How can i do it in a more elegant way?

  • \$\begingroup\$ Do you want this to be 1-2 digits + 5*random uppercased letters + ... or it can be any random string? \$\endgroup\$ Commented Sep 23, 2021 at 11:55
  • \$\begingroup\$ Yes, exactly. I model 31SPZVG2CZ2R8WFU this key as example. So digits+strs.. etc \$\endgroup\$ Commented Sep 23, 2021 at 11:57

2 Answers 2


In your random_char function, you don't use x at all. Replace it with _ (it's conventional in python to use _ for throwaway variables). y could also be renamed to something more descriptive. The name of the function could also be renamed to random_chars since you're generating one or more of them.

Also, use string formatting instead of all those extra variables:

def generate_key():
    return (f"{random.randrange(1, 9)}{random_chars(5)}{random.randrange(1, 9)}{random_chars(2)}" 
            f"{random.randrange(1, 9)}{random_chars(1)}{random.randrange(1, 9)}{random_chars(3)}")

Note that the f-strings are available for Python versions >= 3.6

As a side note, there's this nice exrex which can:

Generate all - or random - matching strings to a given regular expression and more. It's pure python, without external dependencies.

Given some pattern (similar to what you want):

  • (...){4} matches the previous token exactly 4 times.
  • \d matches a digit (equivalent to [0-9])
  • [A-Z]{1,4} matches the previous token between 1 and 4 times, as many times as possible, giving back as needed (greedy)
  • A-Z matches a single character in the range between A (index 65) and Z (index 90) (case sensitive)

Note: I'm not a regex expert so there might be an easier / more correct version of this.

I think you can use this regex which returns exactly the pattern you want: \d{1,2}[A-Z]{5}\d[A-Z]{2}\d[A-Z]{1}\d[A-Z]{3}

Your entire code could be rewritten as:

import exrex

random_key = exrex.getone(r'(\d[A-Z]{1,4}){4}')

Which would generate:


For more information about regular expressions feel free to search on the internet to get familiar with them. For tests, I usually use regex101

  • \$\begingroup\$ As an advice, before accepting an answer try to wait 1-2 days to see alternative solutions/improvements. \$\endgroup\$ Commented Sep 23, 2021 at 12:57
  • \$\begingroup\$ Is this right? The pattern you're using doesn't seem to follow the OP's, for instance having two leading digits. \$\endgroup\$
    – Reinderien
    Commented Sep 23, 2021 at 13:26
  • 1
    \$\begingroup\$ @Reinderien It's just an example. I've specified in my answer that this regex might not be as the one in the question. And with a bit of effort from OP it can be easily modified/customized. More, that is an alternate solution for OP to have in mind ^^. //L.E: added a similar regex \$\endgroup\$ Commented Sep 23, 2021 at 13:40

Instead of treating number and letter parts differently, you could use random.choice for both and save some code:

import random
from string import ascii_uppercase

spec = [
    range(1, 99), *[ascii_uppercase] * 5,
    range(1, 9), *[ascii_uppercase] * 2,
    range(1, 9), *[ascii_uppercase],
    range(1, 9), *[ascii_uppercase] * 3,
print(''.join(str(random.choice(pool)) for pool in spec))

Try it online!

  • \$\begingroup\$ Wow, cool. Could you please explain how this code works exactly? I am just learning \$\endgroup\$ Commented Sep 23, 2021 at 18:40
  • 1
    \$\begingroup\$ It just builds a list of sequences (try print(spec)) and then picks an element from each and concatenates them all. \$\endgroup\$
    – no comment
    Commented Sep 23, 2021 at 18:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.