3.4 — Breaking Code into Functions
One job per function, data in and data out.
Why This Matters
One long main program is hard to test and hard to change. A change request is much easier to add when each job has its own function.
The Idea
def add_item(inventory, name, qty, price):
"""Return the inventory with this item added, or updated if it's already there."""
inventory[name] = {"qty": qty, "price": price}
return inventory
def total_value(inventory):
"""Return the total value of everything in stock."""
total = 0
for details in inventory.values():
total += details["qty"] * details["price"]
return total
Notice what these functions don't do: they don't call input() or print(). They take data in, return data out, and leave the talking to the menu. That's what makes them easy to test.
Signs a function is doing too much: its name has “and” in it (like add_and_save), it runs longer than one screen, or you can't test it without typing things in.
Try It
- Pick one menu option from your project. Move its logic into a function with a docstring.
- Call the function on its own, with test data, and print the result.
- Write one test for it using the pattern from 3.3.
Practice Notebook
Work through more examples, in different contexts, in a Jupyter notebook. Every exercise has a check cell that tells you when your code is right.
How to open it: open the file in VS Code, pick a Python kernel, and run the cells from top to bottom with Shift + Enter.
Common Mistakes
- Printing instead of returning. If the function prints, the caller gets
Noneand can't use the result. - Forgetting
return. Same problem: the caller getsNone. - Changing a variable from outside the function instead of passing it in and returning it.
You're Done With This Lesson When…
Each function does one job, returns its result, and works when you call it without the menu.