0% complete

Functions, modules, and error handling · Lesson 1 of 3

Functions, parameters, and return values

Design small functions with explicit inputs, outputs, and safe defaults.

Lesson

1. Concept and mental model

A function gives a meaningful name to a reusable operation. Define it with def, accept inputs as parameters, and return a result with return. A function that returns a value is easier to test and compose than one that only prints or changes unrelated global state. Keep a function focused on one responsibility and choose names that describe the result or action.

2. How it works

Python supports positional, keyword-only, and default parameters. Avoid mutable defaults such as items=[]: that list is created once when the function is defined and is then shared across calls. Use None as the default and create a fresh list inside the function. Keyword arguments make call sites clearer when several parameters have similar types. Add type hints and a docstring when they improve the contract for users of the function.

3. Use it safely and effectively

Return early for simple guard conditions to reduce nesting, but keep important validation explicit. Do not catch every exception inside a helper and silently return a plausible result; that hides failure from the caller. Build and test the function around examples and edge cases: empty input, one item, invalid data, and normal data. Practice by writing a function that calculates a subtotal and separately test its behavior.

4. Syntax reference

def subtotal(prices: list[float], tax_rate: float = 0.0) -> float:
    return sum(prices) * (1 + tax_rate)

print(subtotal([10.0, 5.0], tax_rate=0.1))

5. Guided walkthrough

Give the function the values it needs as parameters, calculate the result locally, and return it to the caller. Try the function with normal, empty, and boundary inputs; a clear contract makes those cases easy to reason about and test.

6. Common mistakes to avoid

  • Using a mutable list or dictionary as a default argument and unintentionally sharing it between calls.
  • Printing a result inside a helper when callers need to reuse or test that result.

Visual guide

A function contract

  1. Step 01 Inputs

    Receive explicit parameters.

  2. Step 02 Work

    Apply one focused operation.

  3. Step 03 Result

    Return a value or raise a clear error.

Code examples

Worked example
PYTHON
def subtotal(prices: list[float], tax_rate: float = 0.0) -> float:
    return sum(prices) * (1 + tax_rate)

print(subtotal([10.0, 5.0], tax_rate=0.1))
Expected output
16.5
Avoid a shared mutable default
PYTHON
def add_item(item: str, items: list[str] | None = None) -> list[str]:
    result = [] if items is None else items.copy()
    result.append(item)
    return result

print(add_item('tea'))
Expected output
['tea']
Return more than one useful value
PYTHON
def split_total(total: int, people: int) -> tuple[int, int]:
    return divmod(total, people)

print(split_total(17, 3))
Expected output
(5, 2)

Key points

  • Design small functions with explicit inputs, outputs, and safe defaults.
  • Prefer explicit, testable behavior over hidden side effects.
  • Validate assumptions at system boundaries and handle failure deliberately.

Check your understanding

Practice

Why should a list usually not be used as a default parameter value?

Your learning progress

Finish this lesson