Skip to main content

Functions

A function packages a call contract and a body. Calling it binds arguments to parameters, executes the body, and returns a value or raises an exception.

def clamp(value: float, lower: float, upper: float, *, strict: bool = False) -> float:
if lower > upper:
raise ValueError("lower must not exceed upper")
if strict and not lower <= value <= upper:
raise ValueError("value is outside the interval")
return min(max(value, lower), upper)

The * makes following parameters keyword-only, which is useful for behavioral flags whose meaning would be unclear positionally.

Parameter kinds

Python supports positional-only parameters before /, positional-or-keyword parameters, variadic positional *args, keyword-only parameters after *, and variadic keyword **kwargs. Use the narrowest interface that communicates intent; forwarding arbitrary arguments weakens discoverability.

Defaults are evaluated once

Default expressions run when the function is defined, not on every call. Avoid shared mutable defaults:

def collect(item: str, bucket: list[str] | None = None) -> list[str]:
if bucket is None:
bucket = []
bucket.append(item)
return bucket

Return and ownership

Reaching the end without return returns None. Returning multiple comma- separated values constructs a tuple. Document whether a function mutates an argument, returns a new object, performs I/O, or retains references.

Annotations and docstrings

Annotations communicate intended types to readers and tools; the interpreter does not generally enforce them. A concise docstring should explain behavior, important invariants, raised exceptions, and surprising side effects rather than repeat the signature.

Design rules

  • Separate pure calculation from I/O when practical.
  • Prefer explicit result values over printing inside reusable logic.
  • Raise specific exceptions at the boundary where invalid state is recognized.
  • Keep a function at one useful level of abstraction.

Source