Python Tutorial
Python Project: Password Generator
Build random passwords from letters, digits, and symbols, then check that each one meets a length rule.
What you are building
You build a generator that picks characters from letters, digits, and symbols. The length is a number you choose. The program prints three sample passwords and checks that each one is exactly that long.
Run the code at /try. That is the Python editor, not HTML, C, or C++. The examples callrandom.seed(1) so the three samples stay the same every time you click Run. That makes the output easy to check.
Skills used
random.choiceto pick one character from a poolrandom.seedso a tutorial run is repeatablestring.ascii_lettersandstring.digits"".join(...)to glue characters into one password- A length rule: reject or rebuild if
len(password) != n
Build the character pool
A password is a string. The generator does not invent letters from nowhere. It chooses from a pool you define. Keep letters, digits, and symbols in named pieces so you can require one of each later.
Example
import string
letters = string.ascii_letters
digits = string.digits
symbols = "!@#$%^&*?"
pool = letters + digits + symbols
print("Letters:", letters)
print("Digits:", digits)
print("Symbols:", symbols)
print("Pool size:", len(pool))| Piece | Source | Example characters |
|---|---|---|
| Letters | string.ascii_letters | A, z, m |
| Digits | string.digits | 0, 7, 9 |
| Symbols | a short string you write | !, @, # |
Pick N characters with a seed
random.choice(pool) returns one character. Repeat that N times and join. Setting the seed first freezes the sequence. Change the seed and you get a different trio of samples.
Example
import random
import string
random.seed(1)
pool = string.ascii_letters + string.digits + "!@#$%^&*?"
length = 12
password = "".join(random.choice(pool) for _ in range(length))
print(password)
print("Length ok:", len(password) == length)random is fine for a class demo. Real passwords should use the secrets module when it is available, because it is built for tokens. Do not seed secrets. Seed onlyrandom when you need a stable screenshot.
Complete program
Each password starts with one letter, one digit, and one symbol so the mix is not all letters by chance. The rest of the slots fill from the full pool. random.shuffle hides those first three picks. Three samples print, each checked against length N.
Example
import random
import string
random.seed(1)
LETTERS = string.ascii_letters
DIGITS = string.digits
SYMBOLS = "!@#$%^&*?"
POOL = LETTERS + DIGITS + SYMBOLS
N = 12
def make_password(length):
if length < 4:
return None
chars = [
random.choice(LETTERS),
random.choice(DIGITS),
random.choice(SYMBOLS),
]
while len(chars) < length:
chars.append(random.choice(POOL))
random.shuffle(chars)
return "".join(chars)
print("Password generator")
print("Required length:", N)
print()
ok = 0
for i in range(3):
pwd = make_password(N)
if pwd is None:
print("Sample", i + 1, "-> length too small")
continue
passed = len(pwd) == N
if passed:
ok += 1
print("Sample", i + 1, ":", pwd)
print(" chars:", len(pwd), " rule:", "pass" if passed else "fail")
print()
print("Passed", ok, "of 3")Because the seed is 1, a second Run prints the same three strings. If you need a one-off secret on your own machine, drop the seed line and, if you like, swap random.choice forsecrets.choice.
Common mistakes
- Forgetting
"".join. A generator expression of characters is not a password until you join it. - Using
random.randinton character codes and hoping the result is printable. A pool of characters is simpler and safer. - Seeding in production. A fixed seed means anyone can replay the same passwords.
- Checking length with
printonly. Store a boolean and count passes, as the complete program does, so a failed sample cannot hide in the log. - Putting a quote inside the symbol string and breaking the Python string. Keep the symbol set short, or use a triple-quoted string.
How to extend / Practice tasks
Change N, the pool, or the number of samples. Keep the seed until you like the new output.
- Set
N = 16and generate three samples. Confirm every printed length is 16. - Remove digits from
POOLbut still require one digit in the first three picks. Check that each sample still contains at least one character fromstring.digitsusing a loop orany(ch.isdigit() for ch in pwd). - Print a fourth sample using
secretsif the import works, otherwise fall back torandom. Do not seed that fourth sample.
📘 Real-World Deep Dive
A password generator teaches secure randomness — the one place where using the wrong random module is an actual vulnerability. It's also a clean intro to composing character sets and enforcing rules.
What to build
Generate a random password of a given length that is guaranteed to contain at least one lowercase, uppercase, digit, and symbol.
Real-Life Example
import secrets, string
SETS = [string.ascii_lowercase, string.ascii_uppercase,
string.digits, "!@#$%^&*"]
def make_password(length: int = 12) -> str:
if length < len(SETS):
raise ValueError("length too short to satisfy all rules")
# one guaranteed char from each set, then fill the rest
chars = [secrets.choice(s) for s in SETS]
pool = "".join(SETS)
chars += [secrets.choice(pool) for _ in range(length - len(SETS))]
secrets.SystemRandom().shuffle(chars) # don't leave the guaranteed ones up front
return "".join(chars)
print(make_password(16))secrets, not random: the random module is predictable and must never be used for anything security-related.
Expected Output
k7!Qm2vR#pX9tLbZ (random each run)Common mistakes
- Using
random.choicefor passwords is a real flaw — it's seedable and predictable. Use thesecretsmodule. - Guaranteeing one char per set but forgetting to shuffle leaks the pattern (always lower-upper-digit-symbol up front).
- Requiring a symbol on sites that ban symbols will lock users out — make the character sets configurable.
🚀 Performance & Best Practices
secretsis cryptographically secure and plenty fast for password lengths — never trade it for speed here.- Build the pool once from
stringconstants rather than typing character ranges by hand. - Return early with a clear error when the requested length can't satisfy the rules.
🧪 Try It Yourself
- Add flags to toggle each character set on or off and re-check the length is still satisfiable.
- Estimate and print the password's entropy in bits (
length * log2(len(pool))). - Generate a memorable passphrase instead: pick 4 random words from a wordlist with
secrets.choice.