Python Functions

Tutorial 17 of 65 · pythondeck.com Python course

Functions are defined with def and can have positional, keyword, default, *args and **kwargs parameters. Returning multiple values returns a tuple. Functions are first-class objects and can be passed, stored and returned.

Functions package reusable logic with a name, parameters, and return value. They are first-class objects—you can pass them as arguments, store them in variables, and return them from other functions. The standard library is organized as functions and methods you compose, not monolithic programs.

Good functions have a single clear purpose, explicit parameters, and documented contracts—the foundation of testing and modular design. Most scripts are thin orchestration layers calling well-named functions rather than one long procedural block.

Definition: def name(params): body; return sends a value back (or None).

Parameters: positional, keyword, defaults, *args, **kwargs, keyword-only after *.

Docstrings: first statement string documents behavior for help().

Scope: local names inside functions; global/nonlocal for rebinding outer names.

Annotations: def f(x: int) -> str: for hints, not runtime enforcement.

Recursion is supported; watch base cases and stack depth.

Pure functions (no side effects) simplify testing. Impure functions coordinate I/O and state—keep them thin and push logic inward.

Closures capture variables from enclosing scopes—useful for factories and decorators.

Decorators wrap defs; wrappers forward *args and **kwargs to preserve signatures.

Mutable default arguments shared across calls.

Returning multiple values without documenting tuple order.

Functions that do too much—god functions resist testing.

Using mutable global state instead of passing parameters.

Keep parameter lists short; group related options in a dataclass or config object.

Use type hints and docstrings on public APIs.

Raise specific exceptions rather than returning error codes unless style guide says otherwise.

Name functions with verbs (parse_config, save_report).

Split functions that exceed one screen into helpers so each unit tests independently.

Re-read the examples below with these ideas in mind; change variable names and inputs to match your own project.

The program below demonstrates definition. Read the comments on each line, run the code, then change names or values to see how the output shifts.

# Example: Definition
# Run in the REPL or save as a .py file and execute with python.
def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

print(greet("Ada"))
print(greet("Linus", greeting="Hi"))

This sample walks through *args / **kwargs in a small, runnable script. Paste it into the REPL or save it as a .py file before you continue to the next block.

# Example: *args / **kwargs
# Run in the REPL or save as a .py file and execute with python.
def report(*args, **kwargs):
    print("args  :", args)
    print("kwargs:", kwargs)

report(1, 2, 3, user="ada", level=5)

Here is a hands-on illustration of higher order. Follow the inline comments first; only then execute the snippet and compare the result with what you expected.

# Example: Higher order
# Run in the REPL or save as a .py file and execute with python.
def apply(fn, x):
    return fn(x)

print(apply(lambda v: v*v, 9))

The program below demonstrates args kwargs. Read the comments on each line, run the code, then change names or values to see how the output shifts.

# *args collects extra positional values as a tuple
def total(*numbers):  # arbitrary positional count
    return sum(numbers)  # built-in sum over tuple

print(total(1, 2, 3))  # 6
def profile(name, **fields):  # **kwargs -> dict
    return {"name": name, **fields}  # merge dicts

print(profile("Ada", role="dev", city="London"))  # dict output
def both(a, b=0, *rest, flag=False, **meta):  # full signature
    return (a, b, rest, flag, meta)  # echo parameters

print(both(1, 2, 3, 4, flag=True, x=9))  # inspect tuple parts

This sample walks through return multiple in a small, runnable script. Paste it into the REPL or save it as a .py file before you continue to the next block.

# Functions return one object; tuple packing returns many values
def minmax(values):  # compute bounds of a sequence
    return min(values), max(values)  # tuple of two ints

lo, hi = minmax([4, 1, 9, 3])  # unpack at call site
print(lo, hi)  # 1 9
def apply(fn, x):  # higher-order helper
    return fn(x)  # call passed function

print(apply(lambda v: v * 2, 21))  # 42
def greet(name, excited=False):  # default parameter
    text = f"Hello, {name}"  # base greeting
    return text + "!!!" if excited else text  # branch return

print(greet("Python"))  # calm greeting

« Python For Loop All tutorials Python Lambda »