Decomposition
Decomposition means dividing a program into smaller jobs. Give each function a clear responsibility and a name that describes it. One function can call another to perform part of its job.
Read Defining Functions and Parameters & Return first.
Decide on the jobs before writing the code
For a score-report program, identify three jobs:
- Work out the total score.
- Decide whether it reaches a target.
- Display the result.
Name the functions total_score, reaches_target and show_report.
Names such as part1 do not explain what a function does. Pass required data
as parameters, and return a result when another function needs it.
Keep a function focused on one useful job. Avoid a single function that reads input, calculates scores and prints every report; also avoid splitting every line into a separate helper with no clear purpose.
One function calling another
def show_ready():
print("Ready!")
def start_round():
show_ready()
print("Begin.")
start_round()
This prints Ready! and then Begin. on separate lines. start_round calls show_ready; when that call finishes, execution continues with the next statement in start_round.
Call a printing helper on its own line. Writing print(show_ready()) would print Ready! and then None, because the helper does not return a result to display.
Building on a helper
A caller can use the value returned by a helper in a calculation or comparison.
def score(rolls):
return sum(rolls)
def is_winning(rolls):
return score(rolls) >= 100
print(score([40, 35, 30]))
print(is_winning([40, 35, 30]))
is_winning never adds anything up itself — it asks score to do it.
Use a Boolean helper in a condition
def reaches_target(score):
return score >= 10
def count_successes(scores):
count = 0
for score in scores:
if reaches_target(score):
count = count + 1
return count
print(count_successes([8, 12, 10]))
This prints 2. The helper answers one question for each score. The caller uses that Boolean directly in if and keeps the count. Returning from the helper ends that helper call; it does not end count_successes.
Define the helper before the call runs
A helper may appear below the function that uses it, provided its definition has executed before the helper call occurs. In this example, both definitions run before the final call.
def triple_then_add_one(n):
return triple(n) + 1
def triple(n):
return n * 3
print(triple_then_add_one(5))
Both functions exist by the time the last line runs.
See also: Defining Functions, Comparisons and Logical Operators.
Your turn
Complete both functions. total_score(rolls) returns the sum of the rolls. beats_target(rolls, target) calls total_score and returns True only when the total is strictly greater than the target. A total equal to the target returns False.
def total_score(rolls):
# add one return line using sum()
pass
def beats_target(rolls, target):
# add one return line comparing total_score(rolls) to target
pass
print(total_score([10, 20, 30]))
print(beats_target([10, 20, 30], 50))
print(beats_target([10, 20, 30], 60))
Expected output
60
True
False
Your turn: choose a decomposition
A receipt program needs to add item prices, calculate delivery, and display the total. Write three function names and a sentence describing each job. State what each function receives and what it returns or prints.
One possible design is subtotal(prices), delivery_cost(subtotal) and
print_receipt(subtotal, delivery). Other names are suitable if they make
the responsibilities clear. The reporting function should use calculated
results, rather than repeat the calculations.
Practise this in the free Python course, where every exercise checks your code instantly.