Learn How to Build a Simple Password Generator in Python: Absolute Beginners Tutorial

A password generator is one of the best first real-world projects in Python. It is small enough to finish in one sitting, touches the most important beginner concepts — strings, loops, functions, and the standard library — and produces something you can actually use.

This tutorial assumes you have Python 3 installed and know how to run a script from the command line or an editor like VS Code. You do not need any third-party libraries — everything used here ships with Python.

What You Need to Know First

Before writing a single line of the generator, it helps to understand the three Python ideas that power the entire project: strings as sequences of characters, the import statement, and the concept of a function with a return value.

A string in Python is an ordered sequence of characters. Because it behaves like a sequence, Python can pick a random element from it the same way it would pick from a list. That fact is the entire basis of the password generator — the generator picks random characters from a string one at a time and assembles them into a new string.

Note

All modules used in this tutorial — random and string — are part of the Python standard library. You import them with import random and import string at the top of your file. No pip install required.

A function with a return value means the function sends data back to the line that called it. Instead of just printing a password and discarding it, the generator returns the password string so the caller can store it in a variable, pass it somewhere else, or print it — whichever is needed. This is the correct pattern for reusable code.

code builder click a token to place it

Build the correct two-line import block for this project. Click each token in the right order:

your code will appear here...
string from import random import os
Why: The correct block is import random followed by import string. The from keyword is used for a different import style (from random import choice) and is not needed here. The os module is not required for this project.

The random and string Modules

The random module provides tools for making random selections. Two functions are used in this project.

random.choice(seq) returns one randomly selected element from a non-empty sequence. Pass it a string and it returns one character. That is the core of the generation loop.

random.shuffle(lst) reorders a list in place. It does not return a new list — it modifies the existing one. You will use this later to mix guaranteed characters into random positions.

The string module provides pre-built character constants. These three are the most useful for password generation.

Contains
All 26 uppercase and 26 lowercase ASCII letters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
Common use
Always included in a password pool to ensure the result is readable and contains letters.
Contains
The ten digit characters: 0123456789
Common use
Added to the pool to ensure passwords meet "must contain a number" requirements on many sites.
Contains
32 punctuation and symbol characters: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
Common use
Added to meet "must contain a symbol" requirements. Some sites reject certain punctuation characters — you can exclude them by removing them from the pool string.

Building a pool is as simple as concatenating these constants:

python
import string

characters = string.ascii_letters + string.digits + string.punctuation
print(len(characters))  # 94 — the full pool
Pro Tip

If a target site rejects certain symbols, remove them from the pool before generating: characters = characters.replace("'", "").replace('"', ""). The pool is just a string, so standard string methods apply.

Building the Generator Step by Step

Here is the complete minimal version. Read through it once, then the explanation below walks each part.

python
import random
import string

def generate_password(length=12):
    characters = string.ascii_letters + string.digits + string.punctuation
    password = ''.join(random.choice(characters) for _ in range(length))
    return password

print(generate_password())       # 12-character password
print(generate_password(20))     # 20-character password

Let us trace each line.

def generate_password(length=12): defines a function. The parameter length=12 means that if you call the function without an argument, the password will be 12 characters long. You can override it by passing any integer.

characters = ... builds the pool by concatenating three string constants. The pool is 94 characters long when all three are included.

''.join(random.choice(characters) for _ in range(length)) is a generator expression inside join(). For each iteration of range(length), it calls random.choice(characters) and gets back one character. The _ variable is a conventional name for a loop variable whose value you do not need. When the loop finishes, join() assembles all the characters into a single string.

return password sends the finished string back to the caller.

"The secrets module should be used in preference to the default pseudo-random number generator in the random module, which is designed for modelling and simulation, not security." — Python Software Foundation Documentation

That note from the documentation is worth keeping in mind. For a learning exercise, random is perfectly fine. For anything that generates passwords a real user will depend on, replace random.choice with secrets.choice — the rest of the code stays the same.

Adding character-type guarantees

Many sites require at least one uppercase letter, one digit, and one symbol. The version above does not guarantee that — by pure chance it could produce an all-lowercase password. Here is a version that enforces those requirements.

python
import random
import string

def generate_password(length=12):
    if length < 4:
        raise ValueError("Password length must be at least 4.")

    characters = string.ascii_letters + string.digits + string.punctuation

    # Guarantee at least one character from each required category
    password_chars = [
        random.choice(string.ascii_uppercase),
        random.choice(string.ascii_lowercase),
        random.choice(string.digits),
        random.choice(string.punctuation),
    ]

    # Fill the rest of the slots from the full pool
    password_chars += [random.choice(characters) for _ in range(length - 4)]

    # Shuffle so the guaranteed characters are not always at the start
    random.shuffle(password_chars)

    return ''.join(password_chars)

print(generate_password(16))

The list password_chars starts with four guaranteed characters — one uppercase, one lowercase, one digit, one symbol. The rest of the slots are filled from the full pool. After that, random.shuffle(password_chars) mixes all the characters into a random order so the pattern is not predictable.

Warning

random.shuffle() works on a list, not on a string. Python strings are immutable — you cannot shuffle them in place. Always convert the characters to a list first, shuffle the list, then join it back into a string.

spot the bug click the line that contains the bug

This function is supposed to generate a password and return it, but something is wrong. Click the line you think contains the bug, then hit check.

1 import random
2 import string
3
4 def generate_password(length=12):
5 characters = string.ascii_letters + string.digits
6 password = ''.join(random.choice(characters) for _ in range(length))
7 print(password)
The fix: Replace print(password) on line 7 with return password. A function that only prints its result cannot be used in a larger program — the caller receives None instead of the password string. Functions should return their output so the caller decides what to do with it.

How to Build a Password Generator in Python

Follow these five steps in order. Each one is a self-contained decision you make when writing the function, and together they produce a generator that is flexible, correct, and readable.

  1. Import the required modules

    At the top of your script, write import random and import string. These two standard library modules give you random character selection and pre-built character sets without installing anything extra.

  2. Define a character pool

    Create a variable called characters by concatenating string.ascii_letters, string.digits, and string.punctuation. This pool holds every character the generator is allowed to choose from — 94 characters when all three are included.

  3. Write the generate_password function

    Define a function called generate_password that accepts a length parameter with a default of 12. Inside the function, use a list comprehension or generator expression with random.choice(characters) repeated length times, then join the result into a string with ''.join().

  4. Return the result, not print it

    End the function with return password rather than print(password). Returning the value makes the function composable — the caller decides whether to print it, store it, or pass it to another function. Code that only prints its output is harder to test and reuse.

  5. Add character-type guarantees with shuffle

    To ensure the password always contains at least one digit and one symbol, seed the character list with random.choice(string.digits) and random.choice(string.punctuation) before the main loop fills the remaining slots. Call random.shuffle() on the full list so those guaranteed characters land in random positions rather than always appearing at the beginning.

Python Learning Summary Points

  1. The random and string modules are part of the Python standard library. No installation is needed — a single import statement makes them available.
  2. random.choice(seq) selects one element from a sequence at random. Called inside a loop or generator expression, it builds up a collection of random selections one character at a time.
  3. ''.join(iterable) assembles an iterable of strings — including single characters — into one string. It is the correct way to build a string from a list or generator of characters.
  4. Functions should return their output rather than print it directly. Returning makes the function reusable anywhere in a program; printing locks the output to the console.
  5. random.shuffle() operates on a list in place and does not return anything. Convert characters to a list before shuffling, then join the result back into a string.

The password generator project touches five foundational Python skills in a small amount of code: importing modules, defining functions, building strings, using loops and generator expressions, and understanding the difference between printing and returning. Each of those skills transfers directly to larger projects.

check your understanding question 1 of 5

Frequently Asked Questions

The built-in random module is used to select random characters. The secrets module is preferred in production applications because it uses a cryptographically secure random number generator, but random is appropriate for learning the core concepts.

The string module provides pre-built character sets such as string.ascii_letters, string.digits, and string.punctuation. These constants let you define the pool of characters your password draws from without writing out every character manually.

random.choice() accepts a sequence — such as a string or list — and returns one randomly selected element from that sequence. Each call is independent, so calling it inside a loop produces a series of random selections.

random.shuffle() reorders a list in place, randomizing the position of every element. In a password generator it prevents predictable patterns — for example, when you ensure the password contains at least one digit and one symbol, shuffling mixes those guaranteed characters into random positions.

For learning purposes, the random module is a clear and straightforward choice. For any real application where the generated password will protect an actual account, use the secrets module instead. It is designed for cryptographic use and is part of the Python standard library from Python 3.6 onward.

Use the str.join() method with an empty string as the separator: ''.join(my_list). This concatenates every element in the list into a single string with nothing between them, which is exactly what you need when assembling individual password characters.

A character pool is the full string of characters that the generator is allowed to pick from. It is typically built by concatenating constants from the string module, such as letters, digits, and punctuation. The larger and more varied the pool, the harder the resulting password is to guess.

Password length is controlled by the range passed to a for loop or the count argument given to random.choices(). In the tutorial's generate_password() function, the length parameter determines how many iterations the loop runs, and therefore how many characters end up in the final password.