8
\$\begingroup\$

I am learning Python, so pardon me if this is the very crude approach. I am trying to generate a random string using alphanumeric characters. Following is my code:

#Generating random 6 character string from list 'range'.
def code():
    # List of characters [a-zA-Z0-9]
    chars = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9']
    code = ''
    for i in range(6):
        n = random.randint(0,61)    # random index to select element.
        code = code + chars[n]      # 6-character string.
    return code

What I am trying to do is pick six random elements from the list of characters and append them.

Is there any better approach?

\$\endgroup\$
11
\$\begingroup\$

Simplicity + improvements:

  • chars list. Instead of hardcoding all lowercase, uppercase and digit chars - string module provides a convenient constants string.ascii_letters and string.digits
  • random.randint(0,61). Instead of generating random index for further search on chars sequence - random.choice already allows getting a random element from a specified sequence
  • for ... loop is easily replaced with generator expression

The final version:

import random
import string


def random_alnum(size=6):
    """Generate random 6 character alphanumeric string"""
    # List of characters [a-zA-Z0-9]
    chars = string.ascii_letters + string.digits
    code = ''.join(random.choice(chars) for _ in range(size))
    return code

if __name__ == "__main__":
    print(random_alnum())
    print(random_alnum())
    print(random_alnum())

Sample output:

g7CZ2G
bczX5e
KPS7vt
\$\endgroup\$
  • 3
    \$\begingroup\$ You can make chars a global, return code directly and change the i loop variable to _, which is an unofficial sign for "i'm not using this name" This is the best answer so far regardless, though. +1 \$\endgroup\$ – Gloweye Nov 11 at 14:49
  • 9
    \$\begingroup\$ Since this is python 3.6, you can remove the for loop by using ''.join(random.choices(chars, k=6)) \$\endgroup\$ – 409_Conflict Nov 11 at 16:21
  • \$\begingroup\$ Thanks for the answer. It really is an improvement over my code. I will keep the question open for more idea. \$\endgroup\$ – Rahul Nov 11 at 17:09
  • \$\begingroup\$ Also, using the secrets module is smart because it uses the best RNG on the system (random.SystemRandom if it's available, otherwise a weaker RNG). \$\endgroup\$ – Greg Schmit - Reinstate Monica Nov 11 at 23:29
  • 2
    \$\begingroup\$ @GregSchmit Depends if you need a cryptographically secure RNG or not. \$\endgroup\$ – Martin Bonner supports Monica Nov 12 at 9:42
5
\$\begingroup\$

Python's string library has predefined constants for ASCII letters and digits. So after import string, chars could be expressed as chars = string.ascii_letters + string.digits. chars could also become a module-level constant, since it does not change in code(). According to PEP8, the official Style Guide for Python code, the name would then become CHARS.

The random module also features random.choice and random.choices (versions later than Python 3.6), which either draw a single or a given number of samples from a sequence, in your case chars. You could then do

code = "".join(random.choice(chars) for _ in range(6))

or

code = "".join(random.choices(chars, k=6))

depending on what is available to you.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the mention of modules. I wasn't aware of those. \$\endgroup\$ – Rahul Nov 11 at 17:10
2
\$\begingroup\$

You can use a string for chars to avoid the hassle of all the quotes and commas.

\$\endgroup\$
  • \$\begingroup\$ Thanks for pointing that out. \$\endgroup\$ – Rahul Nov 11 at 17:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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