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\$
1

3 Answers 3

13
\$\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\$
6
  • 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, 2019 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\$ Nov 11, 2019 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, 2019 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\$ Nov 11, 2019 at 23:29
  • 2
    \$\begingroup\$ @GregSchmit Depends if you need a cryptographically secure RNG or not. \$\endgroup\$ Nov 12, 2019 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\$
1
  • \$\begingroup\$ Thanks for the mention of modules. I wasn't aware of those. \$\endgroup\$
    – Rahul
    Nov 11, 2019 at 17:10
2
\$\begingroup\$

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

\$\endgroup\$
0

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.