Python projects for beginners: 14 ideas, each with a plan and what it teaches
The best Python projects for beginners are small programs with a rule you can check by hand: a number guessing game, a password generator, a word counter, a command-line to-do list. Each one uses only the standard library and fits in one file. Below are 14, ordered from two hours to a weekend, with the modules each needs, a first version, a stretch goal and the mistake most beginners make.
What Python projects should a beginner build?
Build programs that run in a terminal, use one or two standard library modules and have an answer you can verify. Skip frameworks, graphical interfaces and machine learning for now. They hide what you are trying to learn: how to turn a rule into code, handle bad input, keep data between runs and test the result. The table shows what each project below teaches, so you can choose by skill instead of by title.
| Project | Main idea | Modules | Hours |
|---|---|---|---|
| Number guessing game | Loops and input errors | random | 2 to 3 |
| Password generator and checker | Security basics, strings | secrets, string | 3 to 5 |
| Word frequency counter | Files, regex, counting | pathlib, re, collections | 2 to 4 |
| Command-line to-do list | Arguments, saved state | argparse, json | 4 to 6 |
| Expense tracker from a bank CSV | Money, grouping | csv, decimal | 5 to 8 |
| Downloads folder organizer | Files and safety | pathlib, shutil | 4 to 6 |
| Quiz game from a file | Data separate from code | json, random | 3 to 5 |
| Hangman | State and sets | random | 3 to 5 |
| Weather lookup | HTTP and JSON | urllib or requests | 5 to 8 |
| Caesar and Vigenere ciphers | Modulo arithmetic, tests | unittest | 3 to 5 |
| Contact book | A real database | sqlite3 | 5 to 8 |
| Dice roller with expressions | Regex, seeded randomness | re, random | 4 to 6 |
| Text adventure from a data file | Dictionaries, game state | json | 6 to 10 |
| Flashcards with Leitner boxes | Dates and spaced review | datetime, dataclasses | 6 to 10 |
Use a Python release that still gets updates. As of October 2026 the Python developer guide lists 3.11 and newer as supported and shows 3.10 as end of life, so install 3.12 or newer. Then set up a clean folder for each project:
- Check the version with python3 --version.
- Create a folder, then a virtual environment inside it with python3 -m venv .venv.
- Activate it (source .venv/bin/activate on macOS and Linux, .venv\Scripts\activate on Windows).
- Put your code in one file and your tests in another. Run tests with python -m unittest.
- Run git init and commit each time something works.
myproject/
.venv/ (not committed)
.gitignore (contains .venv/ and __pycache__/)
README.md (what it does, how to run it, one worked example)
app.py (the program)
test_app.py (tests, run with: python -m unittest)
# test_app.py
import unittest
from app import make_greeting
class TestGreeting(unittest.TestCase):
def test_greets_by_name(self):
self.assertEqual(make_greeting('Ada'), 'Hello, Ada!')
if __name__ == '__main__':
unittest.main()Which beginner Python projects need nothing but the standard library?
These eight need no installs. Everything you import ships with Python, so there is no version clash and no setup step to blame when something fails. Do them in order; each one reuses a skill from the one before.
01 Number guessing game
The computer picks a number from 1 to 100, you guess, and it says higher or lower until you get it.
- Modules
- random
- Teaches
- while loops, if and elif, converting text to numbers, catching ValueError.
- First version
- One round, a count of tries, and a message when you win.
- Stretch goal
- Swap roles: you pick a number and the computer guesses it by halving the range each time.
- Time
- 2 to 3 hours.
The mistake is trusting input(). Type “abc” and int() raises ValueError and the program dies. Wrap the conversion in try and except and ask again. The stretch goal is the first algorithm worth knowing: halving the range finds any number from 1 to 100 in at most 7 guesses, because 2 to the power of 7 is 128.
import random
def play(low=1, high=100):
secret = random.randint(low, high)
tries = 0
while True:
raw = input(f'Guess a number from {low} to {high}: ')
try:
guess = int(raw)
except ValueError:
print('Type a whole number.')
continue
tries += 1
if guess < secret:
print('Higher.')
elif guess > secret:
print('Lower.')
else:
print(f'Got it in {tries} tries.')
return tries
if __name__ == '__main__':
play()02 Password generator and strength checker
A command that creates a random password of the length you choose and rates one you type.
- Modules
- secrets, string
- Teaches
- String building, choosing at random safely, simple scoring rules.
- First version
- Generate 16 characters from letters, digits and a few symbols; rate by length and character types.
- Stretch goal
- Refuse any password found in a list of common passwords that you keep in a local file.
- Time
- 3 to 5 hours.
Use secrets, not random, for anything that guards an account. The documentation for random says it is not suitable for security purposes, because its output can be predicted. Do the math you can show: 16 characters drawn from 71 symbols is about 98 bits of randomness, which is the length times log2(71). Print that number next to the password.
03 Word frequency counter
Read a text file and print its twenty most common words with counts.
- Modules
- pathlib, re, collections
- Teaches
- Reading files, regular expressions, Counter, sorting.
- First version
- Lowercase the text, split it into words, count and print the top 20.
- Stretch goal
- Ignore common words like “the”, count two-word phrases, print a bar chart made of # characters.
- Time
- 2 to 4 hours.
Run it on a long public-domain book from Project Gutenberg. Two things go wrong at once: curly apostrophes split “don’t” into two words, and files saved in another encoding raise UnicodeDecodeError. Decide how to treat both and write it in the README.
import re
from collections import Counter
from pathlib import Path
def top_words(path, n=20):
text = Path(path).read_text(encoding='utf-8').lower()
words = re.findall(r"[a-z']+", text)
return Counter(words).most_common(n)04 Command-line to-do list
A program you run as todo.py add, list, done and remove, which keeps its tasks in a file between runs.
- Teaches
- Command-line arguments, saving and loading data, functions that do one job.
- First version
- Four commands, tasks in a tasks.json file next to the script.
- Stretch goal
- Due dates, a list --overdue option, colored output with ANSI codes.
- Time
- 4 to 6 hours.
Three cases break most first versions: the file does not exist on the first run, the file contains broken JSON after a crash, and task numbers shift after a deletion. Give each task a permanent ID that is never reused, and write to a temporary file and rename it so a crash cannot leave half a file.
python todo.py add "Buy milk" python todo.py add "Call the dentist" --due 2026-11-05 python todo.py list python todo.py done 1 python todo.py remove 2
05 Expense tracker from a bank CSV
Read the CSV export from your bank and print what you spent in each category this month.
- Teaches
- Parsing real-world files, exact money arithmetic, grouping data.
- First version
- Rows of date, description and amount; a keyword table (“tesco” is groceries) assigns categories; print totals.
- Stretch goal
- Find recurring charges: the same description about 30 days apart.
- Time
- 5 to 8 hours.
Never use float for money. 0.1 + 0.2 is not 0.3 in floating point, and Decimal fixes that. Bank files also vary: some write expenses as negative numbers, some use a separate debit column, and date formats differ. Put your real file in .gitignore so it never reaches a public repository. The recurring-charge stretch goal is the same problem as the subscription graveyard idea posted on the board.
Read “Expense tracker from a bank CSV” on the board and copy its build prompt →
06 Downloads folder organizer
A script that sorts files in a folder into subfolders by type, with a dry-run mode that shows what it would do.
- Modules
- pathlib, shutil
- Teaches
- Working with the file system, dry runs, never destroying data.
- First version
- Map extensions to folder names (.pdf to Documents, .jpg to Images) and move each file.
- Stretch goal
- Write a log of every move so an undo command can reverse the last run.
- Time
- 4 to 6 hours.
Build --dry-run first and make it the default. If a file with the same name already exists in the target folder, add a number to the new name instead of overwriting. Test on a copy of a messy folder, never on the real one. These two habits, preview first and never overwrite, are what separate a script you trust from one you fear.
07 Quiz game from a question file
A multiple-choice quiz that loads its questions from a JSON file, asks them in random order and reports a score.
- Modules
- json, random
- Teaches
- Keeping data out of code, lists of dictionaries, validating a file you did not write.
- First version
- questions.json with a question, four choices and the right answer; ten questions asked in random order; a final score.
- Stretch goal
- A 15-second timer per question, and a review of the questions you missed.
- Time
- 3 to 5 hours.
Write the file format first, with three example questions, before any code. Then add a check that fails loudly if a question is missing its answer or the answer is not among the choices. Anyone, including you in a month, can then add questions without touching Python.
08 Hangman
A word game with six lives, where the word is shown as underscores and fills in as you guess letters.
- Modules
- random
- Teaches
- Sets, program state, writing a small function for each rule.
- First version
- A list of 20 words, a mask function, six lives, a win and a lose message.
- Stretch goal
- Read words from a file, add difficulty by word length, draw the gallows in ASCII art.
- Time
- 3 to 5 hours.
Keep guessed letters in a set so a repeated guess costs nothing and is easy to detect. Write mask(word, guessed) as its own function and test it: mask('python', {'p', 'o'}) should give 'p _ _ _ o _'. Handle uppercase input and anything that is not a single letter before it reaches the game logic.
Which beginner Python projects use the internet, a database or a data file?
Once the first eight feel easy, these six add one outside thing each: a web service, a database, dates and a parsed text format. They are still single-file programs. The step up is that they can fail for reasons you do not control, so each one asks you to handle errors.
01 Weather lookup
Type a city and the program prints today’s high, low and chance of rain from a public weather service.
- Modules
- urllib.request or the requests package, json
- Teaches
- HTTP requests, JSON, timeouts, handling network failure.
- First version
- Look up a city’s coordinates, request the forecast, print three lines.
- Stretch goal
- Cache each answer in a file for 30 minutes and add a --units option.
- Time
- 5 to 8 hours.
The Open-Meteo service describes its API as needing no authentication for non-commercial use, which makes it a good first API: no account and no key to leak. Always set a timeout, and print a clear message when the city is not found or the network is down. Do not paste an API key into code for any service that needs one; read it from an environment variable.
02 Caesar and Vigenere cipher tool
Encode and decode text with a shifting alphabet, then break a Caesar cipher by trying all 26 shifts.
- Modules
- unittest
- Teaches
- ord and chr, the modulo operator, test cases with known answers.
- First version
- caesar(text, shift) and its inverse, keeping spaces and punctuation as they are.
- Stretch goal
- Vigenere with a keyword, and an automatic Caesar cracker that scores each shift by English letter frequency.
- Time
- 3 to 5 hours.
You get known answers to test against. A Caesar shift of 3 turns HELLO into KHOOR. The classic Vigenere example turns ATTACKATDAWN with the key LEMON into LXFOPVEFRNHR. Put both in your tests on day one. These ciphers are toys that anyone can break. Never use them to protect anything real.
03 Contact book with SQLite
A command-line address book that stores people in a database file and searches by name.
- Modules
- sqlite3
- Teaches
- SQL basics, tables and constraints, parameterized queries, transactions.
- First version
- Add, list, search and delete contacts in contacts.db.
- Stretch goal
- Import from a CSV, export to a CSV, reject duplicate emails with a UNIQUE constraint.
- Time
- 5 to 8 hours.
Pass values to the database with ? placeholders and never build the SQL string with an f-string. That single habit prevents SQL injection, one of the most common ways real applications get broken into. Using the connection as a context manager commits on success and rolls back on an error.
import sqlite3
conn = sqlite3.connect('contacts.db')
conn.execute(
'CREATE TABLE IF NOT EXISTS contacts ('
'id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT UNIQUE)'
)
def add(name, email):
with conn:
conn.execute('INSERT INTO contacts (name, email) VALUES (?, ?)', (name, email))04 Dice roller that understands expressions
Type 2d6+3 or 4d8-1 and get the rolls and the total, the way tabletop games write dice.
- Modules
- re, random
- Teaches
- Regular expression groups, input validation, testing randomness with a fixed seed.
- First version
- Parse a count, a number of sides and an optional plus or minus; print each die and the sum.
- Stretch goal
- Support “4d6 drop lowest”, then roll 100,000 times to check that 2d6 averages 7.
- Time
- 4 to 6 hours.
Random programs are hard to test until you call random.seed(1) at the start of a test, which makes every run repeat. Reject nonsense such as 0d6, 1000000d6 or d. Limit the dice count so a typo does not freeze the terminal.
05 Text adventure from a data file
A small game where you type go north, take key or look, with the rooms, exits and items stored in a JSON file.
- Modules
- json
- Teaches
- Nested dictionaries, game state, parsing commands, separating a game engine from its content.
- First version
- Five rooms, exits between them, one item, one way to win.
- Stretch goal
- Save and load games, a locked door that needs the key, a second ending.
- Time
- 6 to 10 hours.
The engine should know nothing about this particular story. If you can swap in a different JSON file and play a different game without touching the Python, you have designed it well. Write the map on paper first and check that every exit has a matching way back.
06 Flashcards with Leitner boxes
A flashcard drill where cards you get right move to a box you see less often, and cards you miss go back to box one.
- Modules
- datetime, dataclasses, json
- Teaches
- Dates, a data class, saving state, a rule that depends on the calendar.
- First version
- Three boxes: box 1 is due every day, box 2 every third day, box 3 every week. A right answer promotes a card, a wrong one resets it.
- Stretch goal
- Import cards from a CSV, show streaks and the number due tomorrow.
- Time
- 6 to 10 hours.
Store the date each card is next due, not how many days since you saw it, and compare with date.today(). Tests can then pass in a fake today. A later extension is generating the cards: an idea on the board asks to turn the tab you have open into three questions tomorrow, which would feed a drill like this one.
Read “Flashcards with Leitner boxes” on the board and copy its build prompt →
How do I know a beginner Python project is finished?
A project is finished when a stranger can run it from your README and get the result you promised. Use this checklist before you call one done and start the next.
- The README has the command to run it and one worked example with the exact output.
- Bad input gives a clear message, not a traceback. Try an empty string, a negative number and a missing file.
- At least three tests pass with python -m unittest, and one of them covers an edge case.
- The code is in functions, and none of them is longer than about 25 lines.
- It lives in a git repository with a commit history that shows how it grew.
When you finish the list above for several of these, move up. Intermediate Python projects covers scrapers, APIs and packaged tools. For language-neutral projects at all levels, see coding project ideas. If you want a real problem rather than a practice one, the productivity ideas on the board are small enough to build in Python, and you can post an idea of your own.
Frequently asked questions
What are easy Python projects for beginners?
The easiest Python projects are a number guessing game, a word frequency counter and a password generator. Each takes two to five hours, fits in one file and uses only the standard library. Start with the guessing game, because it teaches loops, conditions and input errors in about forty lines.
What Python project ideas teach the most?
The contact book with SQLite and the command-line to-do list teach the most per hour, because they combine input, saved data, errors and tests. Between them you meet files, a database, command-line arguments and structure. Do the guessing game first, then these two, before anything with a web service.
Do I need to install anything for beginner Python projects?
No. All 14 projects above can be built with modules that ship with Python. The weather lookup can use the built-in urllib module, and the requests package is optional. Use a virtual environment for each project anyway, so that when you do install a package it stays inside that project.
How many Python projects should a beginner build?
Finish five to eight small projects before moving on, in any order that keeps you interested. Quality matters more than count: each one should run from a README, handle bad input and have a few tests. Then pick one project that is larger and uses a web service or database.
Can I get a job with beginner Python projects?
Beginner projects alone rarely get a developer job, but they show you can finish things. Pick your two best, add tests and a clear README, and follow them with an intermediate project that has users, data and a deployment. A short write-up of what you learned counts for more than a long list.
Can I use AI tools to help with Python projects?
Yes, if you stay in charge. Write the first version yourself, then ask the tool to review it or explain an error. If the tool writes the code, write the tests first and read every line before you run it. Copying code you do not understand teaches you very little.
Created with AI assistance and edited for this site. Examples are illustrative and do not represent customer research. About the publisher.