Functions and Data Flow
Design small functions with clear contracts, parameters, return values, defaults, and keyword arguments while keeping side effects at program boundaries.
Before this lesson
Write focused function contracts
Distinguish returning from printing
Use defaults and keyword arguments safely
The short answer
A function should have one coherent responsibility, receive required data through parameters, and return a useful result. Keep printing, input, files, and other side effects near the edges so core functions remain easy to test.
Build the mental model
Defining a function creates a callable object; calling it binds arguments to parameters and executes its body. Return sends one object to the caller. A function without an explicit return produces None, which is different from printing a value.
The central idea in this lesson is function contracts. Read the rule, predict a concrete outcome, and then run the smallest example that can confirm or reject the prediction. This separates knowledge from familiarity with syntax.
Make the design choice explicit
Use positional arguments for obvious core inputs and keyword arguments when a call becomes clearer. Defaults are evaluated once at function definition, so never use a mutable list or dictionary as a default; use None and create the object inside.
def calculate_total(prices, tax_rate=0.08):
subtotal = sum(prices)
return subtotal, subtotal * (1 + tax_rate)
def format_receipt(subtotal, total):
return f"Subtotal: USD {subtotal:.2f}\nTotal: USD {total:.2f}"
subtotal, total = calculate_total([12.5, 7.25])
print(format_receipt(subtotal, total))Expected output
Subtotal: USD 19.75 Total: USD 21.33
Trace the example before running it. Identify each input, transformation, returned value, and side effect. Then change one boundary value and explain why the new behavior follows from the rule rather than memorizing the output.
Recognize failure modes
Avoid hidden dependence on globals. Pass collaborators and data explicitly. A long parameter list may reveal that related values deserve a dataclass or that the function has more than one responsibility.
Use a professional practice loop
Turn the concept into a repeatable workflow: write down the expected behavior, implement one coherent change, run a representative example, and retain a regression check. If the result surprises you, capture the exact input and error before changing anything.
Review the program for names, boundaries, and hidden side effects. A solution is complete when another developer can understand its contract, reproduce its setup, and verify both the successful path and one meaningful failure path.
Quick knowledge check
Answer before you reveal.
01Why return a value instead of printing inside every function?
Returned values can be tested, combined, stored, or presented by different interfaces.
02What four steps make the practice loop reliable?
Predict the behavior, make one coherent change, run it, and retain a check that detects regression.
Exercise
Practice challenge
Write separate functions to calculate a trip cost and format its report; keep all input and printing outside the calculation.
Requirements
- The successful path produces the documented result
- At least one boundary or invalid case is handled deliberately
- Calculation or domain logic is separated from console interaction
Optional extension: Add one automated regression check for the most important rule.
Open in Python compilerLesson checkpoint
One small step locks it in
Mark this lesson complete, then keep the momentum going.
Clear up the details
Frequently asked questions
Is function contracts only important in large programs?
No. Small programs reveal the same rules with less noise, and learning the rule early prevents fragile habits from becoming architecture.
Should I memorize every API used here?
No. Memorize the mental model and how to verify behavior. Use documentation for exact names and parameters when needed.
How do I know the exercise is finished?
Meet every success criterion, test at least one boundary or failure case, and explain why the output follows from the code.