Todo List with Save ✅
A todo list is the 'hello world' of persistent apps. Add tasks, list them, mark them done, and, crucially, have them still be there tomorrow. This is where your programs stop forgetting everything the moment they end.
📋 Build this
- Show a menu: add, list, mark done, quit.
- Store tasks as a list of dictionaries, each with a title and a done flag.
- Save to a JSON file on every change, load it on start.
- Survive a missing or empty file gracefully.
Hints, if you want them
Try the spec cold first. Open a hint only when you are properly stuck; the struggle is where the learning is.
Hint 1: The data shape
A task is
{"title": "...", "done": False}. The whole list is a list of those, which is exactly what JSON stores (Lesson 23).Hint 2: Load and save
On start, read the JSON file if it exists, else start with an empty list (Lesson 21). After every add or change, write the whole list back with
json.dumps(tasks, indent=2).Hint 3: The menu loop
A
while True: loop that reads a choice and dispatches with if/elif or a match (Lesson 7). Break on quit, saving first.The reference solution
Yours does not need to match this. There are many good ways to build any of these. Compare only after you have your own working.
Reveal the reference solution
import json
from pathlib import Path
FILE = Path("tasks.json")
def load():
if FILE.exists():
return json.loads(FILE.read_text(encoding="utf-8"))
return []
def save(tasks):
FILE.write_text(json.dumps(tasks, indent=2), encoding="utf-8")
def show(tasks):
if not tasks:
print(" (no tasks yet)")
for i, task in enumerate(tasks, start=1):
mark = "x" if task["done"] else " "
print(f" {i}. [{mark}] {task['title']}")
def main():
tasks = load()
while True:
choice = input("add / list / done / quit: ").strip().lower()
if choice == "add":
title = input(" Title: ")
tasks.append({"title": title, "done": False})
save(tasks)
elif choice == "list":
show(tasks)
elif choice == "done":
show(tasks)
n = int(input(" Which number: "))
tasks[n - 1]["done"] = True
save(tasks)
elif choice == "quit":
save(tasks)
print("Saved. Bye.")
break
if __name__ == "__main__":
main()
add / list / done / quit: add
Title: Write the todo app
add / list / done / quit: add
Title: Eat lunch
add / list / done / quit: list
1. [ ] Write the todo app
2. [ ] Eat lunch
add / list / done / quit: done
1. [ ] Write the todo app
2. [ ] Eat lunch
Which number: 1
add / list / done / quit: list
1. [x] Write the todo app
2. [ ] Eat lunch
add / list / done / quit: quit
Saved. Bye.Stretch goals
- Add a delete option, and a confirm-before-delete (Lesson 41).
- Add due dates with the datetime module (Lesson 24).
- Turn it into a proper CLI tool with argparse (Lesson 27).