Functions
Return Values
Returning single and multiple values, early returns, and None handling
Interview: Core function design — multiple returns and early returns are common interview patterns
The return statement is how functions communicate results back to the caller. Python's flexible return system supports single values, multiple values via tuple packing, early returns for guard clauses, and generator yields. Understanding return semantics is fundamental to writing correct Python functions.
Return Statement Basics
- return expression: Returns the value and exits the function immediately
- return (no value): Returns None explicitly — use for functions that sometimes return a value
- No return statement: Function returns None implicitly — common for side-effect functions
- Multiple returns:
return a, b, cpacks into a tuple — caller unpacks withx, y, z = func()
Early Returns (Guard Clauses)
Early returns reduce nesting and make code more readable by handling edge cases first:
- Guard clause: Check invalid input first and return early — avoids deeply nested if/else
- Bouncer pattern: Named after the "bouncer" at a club — reject bad inputs at the door
- Fail-fast: Return None or raise an exception immediately on invalid state
Returning Multiple Values
Python doesn't truly return multiple values — it returns a single tuple that gets unpacked. For more readable multi-value returns, use collections.namedtuple or dataclasses. This gives named access: result.x instead of result[0].
None Handling
- Check for None: Always use
is None, not== Noneor truthiness checks - Optional return: Functions that may return None should document this clearly
- Walrus operator:
if (result := func()) is not None:— assign and check in one expression
Return in Loops and Finally
A return inside a try block will still execute the finally block before returning. If finally also has a return, it overrides the try block's return. This is a common source of subtle bugs.
Use Cases
Returning multiple computed values from a single function call
Implementing guard clauses for input validation with early returns
Building generators with yield for memory-efficient iteration
Optional returns (return None) for search functions that may not find results
Factory functions that return different functions based on input
Common Mistakes
Forgetting that functions without return statement return None — not undefined or error
Using truthiness check (if result:) instead of (if result is not None:) — fails when result is 0 or empty string
Not unpacking multiple returns correctly — causes "too many values to unpack" errors
Putting return inside finally block — overrides the return value from try
Using deeply nested if/else instead of guard clauses with early returns