PYTHON / CHAPTER 07
Functions and dependable defaults
BeginnerDefine return contracts and avoid shared default state.
By the end of this chapter
- Distinguish return from print
- Explain default argument evaluation
- Use a sentinel for fresh mutable state
The idea
A Python function groups an operation behind named parameters. Return sends its result to the caller; reaching the end without return yields None. Print writes output and is not a substitute for returning data. A small function should state its accepted inputs, output, and any mutation so callers can compose it without depending on hidden behavior.
Default argument expressions are evaluated when the function is defined, not on every call. A list used directly as a default can therefore accumulate changes across calls. Use None as a sentinel when each omitted argument should create a fresh list, then create that list inside the function. Distinguish this intended per-call state from deliberately shared state, and include repeated-call tests.
def append_label(label, labels=None):
if labels is None:
labels = []
labels.append(label)
return labels
print(append_label("a"))
print(append_label("b"))['a'] ['b']
Each omitted argument creates a new list. Passing an existing list still intentionally mutates that supplied list, which should be part of the contract.
Try it yourself
Write a function that returns a new list with one appended label without mutating any caller-supplied list.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
Open Python coding challengesCHECK YOUR UNDERSTANDING