Answer in one line:

''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))

or even shorter starting with Python 3.6 using random.choices():

''.join(random.choices(string.ascii_uppercase + string.digits, k=N))

A cryptographically more secure version: see this post

''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))

In details, with a clean function for further reuse:

>>> import string
>>> import random
>>> def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
...    return ''.join(random.choice(chars) for _ in range(size))
...
>>> id_generator()
'G5G74W'
>>> id_generator(3, "6793YUIO")
'Y3U'

How does it work ?

We import string, a module that contains sequences of common ASCII characters, and random, a module that deals with random generation.

string.ascii_uppercase + string.digits just concatenates the list of characters representing uppercase ASCII chars and digits:

>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

Then we use a list comprehension to create a list of 'n' elements:

>>> range(4) # range create a list of 'n' numbers
[0, 1, 2, 3]
>>> ['elem' for _ in range(4)] # we use range to create 4 times 'elem'
['elem', 'elem', 'elem', 'elem']

In the example above, we use [ to create the list, but we don't in the id_generator function so Python doesn't create the list in memory, but generates the elements on the fly, one by one (more about this here).

Instead of asking to create 'n' times the string elem, we will ask Python to create 'n' times a random character, picked from a sequence of characters:

>>> random.choice("abcde")
'a'
>>> random.choice("abcde")
'd'
>>> random.choice("abcde")
'b'

Therefore random.choice(chars) for _ in range(size) really is creating a sequence of size characters. Characters that are randomly picked from chars:

>>> [random.choice('abcde') for _ in range(3)]
['a', 'b', 'b']
>>> [random.choice('abcde') for _ in range(3)]
['e', 'b', 'e']
>>> [random.choice('abcde') for _ in range(3)]
['d', 'a', 'c']

Then we just join them with an empty string so the sequence becomes a string:

>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
Answer from Ignacio Vazquez-Abrams on Stack Overflow
Top answer
1 of 16
3307

Answer in one line:

''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))

or even shorter starting with Python 3.6 using random.choices():

''.join(random.choices(string.ascii_uppercase + string.digits, k=N))

A cryptographically more secure version: see this post

''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))

In details, with a clean function for further reuse:

>>> import string
>>> import random
>>> def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
...    return ''.join(random.choice(chars) for _ in range(size))
...
>>> id_generator()
'G5G74W'
>>> id_generator(3, "6793YUIO")
'Y3U'

How does it work ?

We import string, a module that contains sequences of common ASCII characters, and random, a module that deals with random generation.

string.ascii_uppercase + string.digits just concatenates the list of characters representing uppercase ASCII chars and digits:

>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.digits
'0123456789'
>>> string.ascii_uppercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'

Then we use a list comprehension to create a list of 'n' elements:

>>> range(4) # range create a list of 'n' numbers
[0, 1, 2, 3]
>>> ['elem' for _ in range(4)] # we use range to create 4 times 'elem'
['elem', 'elem', 'elem', 'elem']

In the example above, we use [ to create the list, but we don't in the id_generator function so Python doesn't create the list in memory, but generates the elements on the fly, one by one (more about this here).

Instead of asking to create 'n' times the string elem, we will ask Python to create 'n' times a random character, picked from a sequence of characters:

>>> random.choice("abcde")
'a'
>>> random.choice("abcde")
'd'
>>> random.choice("abcde")
'b'

Therefore random.choice(chars) for _ in range(size) really is creating a sequence of size characters. Characters that are randomly picked from chars:

>>> [random.choice('abcde') for _ in range(3)]
['a', 'b', 'b']
>>> [random.choice('abcde') for _ in range(3)]
['e', 'b', 'e']
>>> [random.choice('abcde') for _ in range(3)]
['d', 'a', 'c']

Then we just join them with an empty string so the sequence becomes a string:

>>> ''.join(['a', 'b', 'b'])
'abb'
>>> [random.choice('abcde') for _ in range(3)]
['d', 'c', 'b']
>>> ''.join(random.choice('abcde') for _ in range(3))
'dac'
2 of 16
658

This Stack Overflow quesion is the current top Google result for "random string Python". The current top answer is:

''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(N))

This is an excellent method, but the PRNG in random is not cryptographically secure. I assume many people researching this question will want to generate random strings for encryption or passwords. You can do this securely by making a small change in the above code:

''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N))

Using random.SystemRandom() instead of just random uses /dev/urandom on *nix machines and CryptGenRandom() in Windows. These are cryptographically secure PRNGs. Using random.choice instead of random.SystemRandom().choice in an application that requires a secure PRNG could be potentially devastating, and given the popularity of this question, I bet that mistake has been made many times already.

If you're using python3.6 or above, you can use the new secrets module as mentioned in MSeifert's answer:

''.join(secrets.choice(string.ascii_uppercase + string.digits) for _ in range(N))

The module docs also discuss convenient ways to generate secure tokens and best practices.

🌐
Plain English
plainenglish.io › blog › lets-build-a-random-character-generator-in-python-7f2f42bea5d1
Let's Build a Random Character Generator in Python
Using Python, we'll make a program that will create an endless supply of random characters for a fantasy role playing game, complete with detailed descriptions and personality traits.
🌐
Reddit
reddit.com › r/python › i made a d&d 5e character generator in python, could i get some feedback on the code?
r/Python on Reddit: I made a D&D 5e Character Generator in Python, could I get some feedback on the code?
March 17, 2021 -

I made this as a quarantine project probably some time around May/June of last year. It was made in a span of probably a week or two. What initially made me think about making a character generator was that back when we were allowed to play D&D our group was somewhat notorious for accidentally stumbling on random NPCs and I figured something like this could help a DM out if they use a laptop while they run their game.

This project was also my foray into Python, and was just for fun.

I wanted to post it here to get some feedback on what I could do better because I'm sure parts of it are very sloppy.

https://github.com/ThatCoolNerd/dnd_5e_character_generator

Some things that I think could be improved:

  • How the stereotypical alignment and class is generated

  • How the stats are optimized on a per-class basis

  • How names are selected

Thanks for reading!

Top answer
1 of 2
6
def roll_stats():
    a = random.randint(1, 6)
    b = random.randint(1, 6) 
    c = random.randint(1, 6)
    d = random.randint(1, 6)
    list = [a, b, c, d]

Call it dice or something more descriptive then list. You can also use list = [random.randint(1,6) for x in xrange(4)] rather then creating the variables separately.

    list.sort()
    add = sum(list[1:4])

Instead of sorting it and slicing it use: list.remove(min(list))

    return add

Don't assign variables just to return them on the next line, use return sum(list[1:4])

def pow_mod():
    a = "|+1 to hit on mele attack rolls| "
    b = "|+1 damage on mele attack rolls|"

    if pow >= 15 and pow < 17:

Don't take input to a function from global variables, pass it as a parameter

        return a
    if pow >= 17:
        return a + b
    else: 
        return " ~no modifiers~"

You return strings, but conceptually you are returning a list of modifiers. I suggest returning the list. You can then format the list anyway you like in the caller.

You've got a number of functions very similiar to this, it suggests moving some of the details into data structures. I'd do it like this:

POW_MODIFIERS = [
# specify minimum and maximum stat the modifier applies to
    (15, 9999, "+1 to hit on mele attack rolls"),
    (17, 9999, "+1 damage on mele attack rolls")
]

def calc_modifiers(stat, modifiers):
    return [modifier for minimum, maximum, modifier in modifiers if minimum <= state <= maximum]

def format_modifiers(modifiers):
    if modifiers:
       return ' '.join('|%s|' % modifier for modifier in modifiers) 
    else:
       return ' ~no modifiers~ '

By creating lists like POW_MODIFIERS for all your stats, you can reuse the functions for all the different stats. You should be able to apply similiar techniques to your other decisions. I'd also look at storing the data in a seperate file, perhaps using JSON.

2 of 2
4

I would suggest moving all your top level code into a main() routine and collecting it all in one place rather than having top level code and routines interspersed. I like to structure my code like this:

import sys

def main():
    ... top level code ...
    routine1()
    ...
    routine2()
    ...
    all_done()

def routine1():
    ... do work here ...

def routine2():
    ... do work here ...

def all_done():
    ... finish up ...

if __name__ == '__main__':
    main(sys.argv)

By doing it this way, if my code is in a file named, say, 'code.py', I can play with in the python interpreter by doing, eg.

python
>>> import code
>>> code.all_done()       # test routine all_done() by itself
>>> ^D

With the top level code interspersed with the function definitions, when you try to import code, it all gets run. You can't run the pieces independently.

🌐
Plain English
python.plainenglish.io › lets-build-a-random-character-generator-in-python-7f2f42bea5d1
Let’s Build a Random Character Generator in Python | by Josh Petty | Python in Plain English
January 21, 2021 - Using Python, we’ll make a program that will create an endless supply of random characters for a fantasy role playing game, complete with detailed descriptions and personality traits. ... The character generator provides you with all the data you need for a well-rounded NPC.
🌐
GitHub
gist.github.com › 6302896
Character Creator Python Program · GitHub
Character Creator Python Program. GitHub Gist: instantly share code, notes, and snippets.
Find elsewhere
🌐
Flexiple
flexiple.com › python › generate-random-string-python
How to generate a random string in Python? - Flexiple
Random.choices - returns elements at random. Here characters can not be unique. Random.sample - returns unique elements. So while generating a random string in Python, If you are okay with repeating characters you can use the first method, and the second if you want unique characters.
🌐
PYnative
pynative.com › home › python › random › generate random strings and passwords in python
Generate Random Strings and Passwords in Python
February 16, 2022 - Generate a random string of any length in Python. create a random password with lower case, upper case letters, digits, and special characters.
🌐
GitHub
github.com › topics › character-generator
character-generator · GitHub Topics · GitHub
A character creator/generator for 5e with all source races and classes and names generated via Neural Networks · python dnd neural-network character-creation character-generator 5e
🌐
PyPI
pypi.org › project › StringGenerator
StringGenerator · PyPI
The template language is superficially similar to regular expressions but instead of defining how to match or capture strings, it defines how to generate randomized strings. A very simple invocation to produce a random string with word characters of 30 characters length: from strgen import StringGenerator as SG SG(r"[\w]{30}").render() 'wQjLVRIj1sjjslORpqLJyDObaCnDR2' ... The current package requires Python 3.6 or higher.
      » pip install StringGenerator
    
Published   Mar 20, 2021
Version   0.4.4
🌐
w3resource
w3resource.com › python-exercises › modules › python-module-random-exercise-3.php
Python: Generate a random alphabetical character, string and alphabetical strings of a fixed length
August 11, 2025 - import random import string print("Generate a random alphabetical character:") print(random.choice(string.ascii_letters)) print("\nGenerate a random alphabetical string:") max_length = 255 str1 = "" for i in range(random.randint(1, max_length)): str1 += random.choice(string.ascii_letters) print(str1) print("\nGenerate a random alphabetical string of a fixed length:") str1 = "" for i in range(10): str1 += random.choice(string.ascii_letters) print(str1)
🌐
GeeksforGeeks
geeksforgeeks.org › how-to-generate-a-random-letter-in-python
How to generate a random letter in Python? | GeeksforGeeks
September 8, 2022 - Python provides rich module support ... us to generate random numbers and letters. There are multiple ways we can do that using various Python modules. The string module has a special function ascii_letters which returns a string containing all the alphabets from a-z and A-Z, i.e. all the lowercase and uppercase alphabets. Using random.choice() we can choose any of the particular characters from that ...
🌐
OneCompiler
onecompiler.com › python › 3x2z8wwhm
dnd character generator - Python - OneCompiler
Following is a sample python program which takes name as input and print your name with hello.
🌐
Reddit
reddit.com › r/python › d&d 3.5 random character generator written in python
r/Python on Reddit: D&D 3.5 Random Character Generator written in Python
January 12, 2017 -

hi! I made a character generator for D&D. it includes name, appearance, stats, weapons, weapon data, armor, religion, alignment, and a few other goodies.

while i'm happy with the result, I am not so happy with the back end. a lof of the formatting feels wrong, and i'' guessing any sensible programmer would scoff at some of the decisions i made.

with all that said, heres the program! any criticisms/yelling about how bad i am would be appreciated

thank you!

Top answer
1 of 5
12

Very cool, I'm working on something similar!

Some suggestions:

  • I'm not sure if you mean to use randrange or randint. Based on how you use it I think you mean randint as the max stat roll in D&D is 18 but randrange(8, 18) means that the max value you'll get is 17.

  • You might want to add some comments or more descriptive function names. While I understand what ls does, I'm not sure what it stands for.

  • I would include the Open Game License to make sure your project is on the up and up. Also review the license and basically, if it is from D&D but it isn't on SRD20 then take it down.

  • In the README I would include examples of how to use your program, as well as list the dependencies which in your case is requirements.txt. For example, you can input the class on the first line to skip the second input, but that isn't ever document.

  • You only use console for its clear command. Instead of forcing your users to install another library to use your tool I would write a small clear function. Something like:

    import os
    
      def clear():
          if os.name == 'nt':
              os.system('cls') # Windows
          else: 
              os.system('clear') # POSIX
  • My final suggestions would just be formatting. Function names should be cased_like_this rather than likeThis. I would also lowercase Data.py.

EDITS:

  • Forgot to mention that you might want to get the stat values in a way more accurately depicting the distribution you would get when rolling dice. So rather than a single 8-18 random value you might want something like:

    sum(randint(1, 6) for _ in range(3))

    That way you don't get 18's as often as you get 10's, which is the case when actually rolling dice.

  • Okay so I've been playing with it more, actually I made a fork to mess with, and you should probably include a way to save the output into a file.

  • I would also include error checking. If someone puts in bad input the program crashes.

  • getRace also gets the class. I would separate these into two functions.

  • This project could heavily benefit from using some classes. In particular, a class that creates the character.

I really like this project. Feel free to DM me if you have any questions.

2 of 5
3

Looks pretty good to start! There are a few formatting changes that you might want to integrate (using [] and {} instead of list() and dict(), 4 spaces instead of tabs, etc), but the structure looks fairly straight forward.

I'll have a closer look at this later today, but one suggestion would be to standardize the generate function and move all the constants into the data structure. As it stands, you've got a lot of data mixed in with the functional bits of code, which makes it more difficult to modify in future.

E.g.

RACE_CONSTANTS = {
    "Human": {
        "height_min": 60,
        "height_max": 80
    },
    "Dwarf": {
        "height_min": 48,
        "height_max": 56
    }
}

def generate(race):
    stats = RACE_CONSTANTS[race]

    height = random.randint(stats['height_min'], stats['height_max'])
🌐
AskPython
askpython.com › home › how to generate random strings in python
How to Generate Random Strings in Python - AskPython
January 7, 2025 - The list of characters used by Python strings is defined here, and we can pick among these groups of characters. We’ll then use the random.choice() method to randomly choose characters, instead of using integers, as we did previously. Let us define a function random_string_generator(), that does all this work for us.
🌐
Testmuai
testmuai.com › testmu ai › blog › how to use python for random string generation | testmu ai
How To Use Python For Random String Generation | TestMu AI (Formerly LambdaTest)
January 11, 2026 - It can produce random integers, floating-point numbers, sequences, and many more. The module allows programmers to create random strings in Python with altered compositions and lengths. The generation of various data sets and the modeling of random events are made possible by this functionality.
🌐
Educative
educative.io › answers › how-to-generate-a-random-string-in-python
How to generate a random string in Python
Python is a ​powerful language that allows programmers to perform various tasks using built-in libraries. A random string, for example, can be generated using the built-in libraries. Two libraries are imported for this: ... Using this random module, different random strings can be generated. random.choice() is used to generate strings in which characters may repeat, while random.sample() is used for non-repeating characters.
🌐
GitHub
gist.github.com › DHCross › 2a16f2607b4e7221c4349e2cab4d4c1f
Python character generator · GitHub
Python character generator. GitHub Gist: instantly share code, notes, and snippets.