Writing Your Own Functions
Choose Clear Function Boundaries
Knowing how to define a
There is no formula that always gives the perfect answer. There are useful signs.
Start with one clear responsibility
Look back at the Chapter 7 menu. Its commands already name separate responsibilities:
| Command | Responsibility | Possible function |
|---|---|---|
add | ask for and store one item | add_item(items) |
list | display the stored items | show_items(items) |
count | display how many are stored | show_count(items) |
Those boundaries are natural because each function name describes one complete action.
Compare that with:
def handle_everything():
# print the title
# run the menu loop
# add items
# list items
# count items
# say goodbye
pass
This is technically a function, but its name and body still hide the whole program in one place. Putting many responsibilities inside a function does not make them easier to understand.
At the other extreme:
def print_number(number):
print(number)
def add_one(number):
return number + 1
Tiny functions can be useful, but splitting every simple
A good first question is:
Can I describe this function’s job with one short verb phrase?
Show the stored items passes. Handle the menu and all its commands and also print the final report is a warning that more than one responsibility is mixed together.
Decide what crosses the boundary
Once the job is clear, ask two more questions:
What information does the function need?
Does the caller need a
back?
For example:
def count_message(items):
return f"Items stored: {len(items)}"
The function needs the items is a
This function has a different responsibility:
def show_count(items):
print(f"Items stored: {len(items)}")
It also needs items, but its job is specifically to display the count. It prints and does not need to return the message.
Both designs can be sound. Choose based on what the caller needs.
Keep the main path readable
The purpose of the Chapter 8 refactor is not to reduce the total number of lines. Function definitions may make the file slightly longer.
The improvement appears in the menu
if command == "add":
add_item(items)
elif command == "list":
show_items(items)
elif command == "count":
show_count(items)
The loop now reads like a table of choices. Someone who wants the overall plan can stay there. Someone who wants the details of listing can go directly to show_items.
That is structure: different levels of detail, each with a clear place.
A practical checklist
Before extracting a function, ask:
Can I give the operation a precise name?
Does it have one main responsibility?
Are its needed parameters clear?
Is it clear whether it should print, return, or change something?
Does the caller become easier to read?
You will get better at these choices by making them, reading the result, and revising.
Which function has the clearest single responsibility?
A function builds a cleaned command that an if statement will compare. What should the function do?