Python Basics for Vibe Coders

Python Basics for Vibe Coders, Part 10: Build a To-Do List with Everything You've Learned

Build a Python to-do list from variables, lists, dictionaries, functions, loops, and conditionals, read it line by line, plus a 9-point AI code checklist.

Python Basics for Vibe Coders, Part 10: Build a To-Do List with Everything You've Learned

From Part 1 through Part 9, we looked at variables, conditionals, loops, lists, dictionaries, functions, errors, and files one at a time. Real programs that an AI writes for you are usually built from combinations of these tools, not new syntax. This is the last of the 10 parts in the series "Python Basics for Vibe Coders." We'll put together what you've learned to build a small to-do list program and read it line by line. The examples are written for Python 3.15, and I ran them in Python 3.14.2 to check the results.

Illustration on a dark background of blue and orange toy blocks assembling into a checklist board with empty rows, two of them checked

Key Takeaways

  • A program is a combination, not new syntax. First decide the shape of your data, then write functions that work with that data.
  • A to-do list can be represented as "a list of dictionaries." todos[0]["done"] means "whether the first to-do is done."
  • If a function appends to a list, the list outside the function changes even without a return.
  • Numbers on screen (starting at 1) and list indexes (starting at 0) are off by one. Don't forget number - 1.

Snap it together like LEGO, but order matters

This part is a lot like building with LEGO: you fit together pieces you already have. There's one difference, though. LEGO pieces end up the same shape no matter what order you snap them in, but in code, changing the order changes the result ("top to bottom" from Part 1). If you call a function before you define it, you get an error. If you print before you mark something done, the mark won't show.

The full to-do list program

todos = []

def add_todo(title):
    todos.append({"title": title, "done": False})

def show_todos():
    for i, todo in enumerate(todos, start=1):
        mark = "✔" if todo["done"] else " "
        print(f"{i}. [{mark}] {todo['title']}")

add_todo("Install Python")
add_todo("Learn variables")
todos[0]["done"] = True
show_todos()
1. [✔] Install Python
2. [ ] Learn variables

Reading it line by line: where did you learn this?

CodeWhat it doesRelated part
todos = []Gives an empty list the name todosParts 2 and 5
{"title": title, "done": False}One to-do = a dictionary with a title and a done flagParts 2 and 6
def add_todo(title):A function that adds a to-doPart 7
todos.append(...)Adds a to-do to the end of the listPart 5
for i, todo in enumerate(...)Loops over each to-do along with its numberPart 4
"✔" if todo["done"] else " "A check mark if done, a blank if notPart 3
f"{i}. [{mark}] {todo['title']}"Builds one line of textPart 2
todos[0]["done"] = TrueMarks the first to-do as doneParts 5 and 6

Only two tools are new.

  • enumerate(items, start=1) gives you each item along with a number starting at 1. That's why i becomes 1, 2, and so on.
  • A if condition else B is a one-line conditional that picks A if the condition is true and B if it's false.

Read todos[0]["done"] one step at a time, from left to right. First, [0] picks the first to-do (a dictionary) from the list. Then you look at that dictionary's "done" key. When you run into a long line like data["items"][0]["name"] in AI code, unpack it the same way, one step at a time from the left.

Common trap: with no return, can add_todo do anything?

In Part 7, we saw that a function without return gives back None. Yet add_todo has no return, and the list still grows. That's because the function changes the list itself. append doesn't build a new list and give it back; it adds an item to the list that's already there.

So when you read a function, tell these two kinds apart:

  • Functions that give back a value: they hand over a result with return (for example, add_tax from Part 7).
  • Functions that change something directly: they modify a list or dictionary in place (for example, add_todo).

If you notice in AI code that "data somewhere else changed after I called this function," check whether it's the second kind.

Wrapping up for vibe coders: a checklist for reviewing AI code

Here's what this series covered, turned into things to check when you get code from an AI.

  1. Where you run it: Did you tell terminal commands apart from Python code? Did you run it from the folder the file is in? (Part 1)
  2. Value types: Is a value you need to calculate with actually a string? (Part 2)
  3. Condition order: Do narrower conditions come first? Are the results right at the boundary values? (Part 3)
  4. Where loops end: Is the end value of range right? Does the while loop ever stop? (Part 4)
  5. Numbering: Are you mixing up indexes that count from 0 with on-screen numbers that count from 1? (Part 5)
  6. Missing keys: Are you reading a key that might not exist with []? (Part 6)
  7. Returned values: Did the code only print and forget to return? (Part 7)
  8. Hidden errors: Is a bare except: swallowing every error? (Part 8)
  9. Files: Did you check whether it overwrites, and whether encoding="utf-8" is there? (Part 9)

Try it yourself: add a mark_done function

Add a mark_done(number) function to the code above that takes a number and marks that to-do as done. On-screen numbers start at 1, but list indexes start at 0, so you need number - 1.

todos = [
    {"title": "Install Python", "done": True},
    {"title": "Learn variables", "done": False},
]

def mark_done(number):
    todos[number - 1]["done"] = True

def show_todos():
    for i, todo in enumerate(todos, start=1):
        mark = "✔" if todo["done"] else " "
        print(f"{i}. [{mark}] {todo['title']}")

mark_done(2)
show_todos()
1. [✔] Install Python
2. [✔] Learn variables

If you see ✔ next to number 2 after mark_done(2), you've got it. If you pass a number that doesn't exist, like 3, you'll get the IndexError from Part 5. Good next exercises: handle that with try / except from Part 8, or extend the program to save the list to a file as in Part 9.

What to learn next

  • Saving the to-do list to a file and loading it back (building on Part 9)
  • Classes and modules: grouping code into bigger units
  • The standard library: beyond the json and pathlib you got a taste of in Parts 6 and 9, there are many built-in tools for things like dates and times
  • Small automation scripts: organizing files, handling repetitive tasks

With these basics, you can ask the AI "Why did you do it this way?" and judge whether the answer makes sense. As a starting point for vibe coding, that's enough.

Full series list

  1. Where Do You Run the Code AI Gives You?
  2. Variables and What = Really Means
  3. if, elif, else and the Order Bug
  4. for and while Loops and the range Trap
  5. Lists and Indexes That Start at 0
  6. Dictionaries, Looking Up Values by Key, and KeyError
  7. Functions, and Why print Is Not return
  8. Read Error Messages from the Bottom Up
  9. Saving Files and encoding="utf-8"
  10. Build a To-Do List with Everything You've Learned (this post)
Back to list