This is a toy project and I am a beginner in Python.

I need to create 10 random 3-letter strings, where characters are a - z.

This is my implementation:

import random

def random_char():
    return random.randint(97, 122)

three_letter_words = []
for i in range(0, 10):
    three_letter_words.append(chr(random_char()) + chr(random_char()) + chr(random_char()))

I really do not like the part where I call chr(random_char()) 3 times.

How can I improve this to make it more compact and cleaner?


3 Answers 3


Python 3.6 introduced random.choices, which allows you to write this even more succinctly than using random.choice:

from random import choices
from string import ascii_lowercase

three_letter_words = ["".join(choices(ascii_lowercase, k=3)) for _ in range(10)]
  • 1
    \$\begingroup\$ @KorayTugay It is shorter than ["".join(choice(ascii_lowercase) for _ in range(3)) for _ in range(10)]. IMO this makes it also easier to read. Whether or not it is easier to read than writing out the for loop, that depends a bit on how used you are to list comprehensions. I think this one is not yet pushing it so far as to become unreadable. \$\endgroup\$
    – Graipher
    Jul 10, 2018 at 20:20
  • 2
    \$\begingroup\$ I would not recommend doing from random import choices. choices isn't a comprehensive enough name to stand on its own like that. random.choices(...) seems like a much more readable choice (pun intended). \$\endgroup\$
    – Alexander
    Jul 10, 2018 at 22:54
  1. a much more readable way of specifying that character range:

  2. To get a string of n characters:

    ''.join([random.choice(string.ascii_lowercase) for _ in range(n)])

In addition to @l0b0's answer:

To generate cryptographically secure random strings (since this is a toy project, why not use a CSPRNG? it's a useful thing to learn):

import string

# only needs to be initialized once
import random
csprng = random.SystemRandom()

# alternatively, the "secrets" module is meant for generating strong csprng numbers
import secrets
csprng = secrets.SystemRandom()

# uses @Graipher's suggestion of .choices()
def random_string(len = 3, charsets = string.ascii_lowercase):
    return ''.join(csprng.choices(charsets, k = len))

three_letter_strings = [random_string() for _ in range(10)]


example output:
['ebi', 'hbg', 'hlm', 'rhp', 'eka', 'uja', 'uhi', 'lju', 'vvf', 'qtj']

alternatively, below is likely faster
if you want to do this a lot more than 10 times

see: https://stackoverflow.com/a/2970789

import itertools

three_letter_strings = [random_string() for _ in itertools.repeat(None, 10)]


Tested with Python 3.6.5

  • 1
    \$\begingroup\$ You should probably only be using one SystemRandom instance. Also, if you're extending an empty list with a generator expression you might as well just use a list comprehension. Lastly, your use of itertools.repeat just produces the same string 10 times - this may be random in the XKCD sense but probably isn't what OP was after. \$\endgroup\$ Jul 10, 2018 at 9:51
  • \$\begingroup\$ @IzaakvanDongen thanks for your feedback, I've edited my answer to include your suggestions (and fixed itrertools.repeat, I'd forgotten that it returns the same thing N times, instead of calling it N times). \$\endgroup\$
    – esote
    Jul 10, 2018 at 11:35
  • 1
    \$\begingroup\$ Wow, it is actually faster: %timeit [0 for _ in range(10000000)]: 325 ms ± 1.38 ms, %timeit [0 for _ in repeat(None, 10000000)]: 184 ms ± 1.72 ms. That's a factor 2! (Of course this is only relevant as long as looping dominates the timing and not the execution of the function itself.) \$\endgroup\$
    – Graipher
    Jul 10, 2018 at 11:59

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.