Site

Functions — Python Functions

Tutorial 4.0  •  Python / Learn

4.0 What This Teaches

This tutorial covers how Python defines and calls functions:

4.1 Defining Functions

Use def followed by the function name, parenthesized parameters, and a colon. The body is indented:
def greet(name):
    print(f"Hello, {name}!")

def add(a, b):
    return a + b

greet("Alice")
result = add(3, 4)
print(result)  # 7
A function that doesn't hit a return statement returns None implicitly. Functions can return multiple values as a tuple: return x, y.

4.2 Default Parameters and Keyword Arguments

def greet(name, greeting="Hello", punctuation="!"):
    return f"{greeting}, {name}{punctuation}"

print(greet("Alice"))                        # Hello, Alice!
print(greet("Bob", greeting="Hi"))           # Hi, Bob!
print(greet("Carol", punctuation="."))       # Hello, Carol.
print(greet("Dave", "Hey", "."))             # positional: Hey, Dave.
Parameters with defaults come after required parameters. Keyword arguments at the call site can appear in any order and make the code more readable.

4.3 *args and **kwargs

def total(*args):
    return sum(args)

def show(**kwargs):
    for key, value in kwargs.items():
        print(f"  {key}: {value}")

print(total(1, 2, 3, 4))   # 10

show(name="Alice", age=30, city="Portland")
# name: Alice
# age: 30
# city: Portland
*args collects extra positional arguments into a tuple. **kwargs collects extra keyword arguments into a dict. You can use any names, but args and kwargs are the convention.

4.4 Type Hints

def add(a: int, b: int) -> int:
    return a + b

def first_positive(values: list[int]) -> int | None:
    for v in values:
        if v > 0:
            return v
    return None
Type hints are optional and not enforced at runtime. They document intent and enable tools like mypy and IDE autocompletion to catch type errors before you run the code. For Python 3.9 and earlier, import from typing: from typing import List, Optional.

4.5 First-Class Functions

Functions are objects. You can assign them to variables, pass them as arguments, and return them from other functions:
def square(x):
    return x * x

def apply(func, values):
    return [func(v) for v in values]

results = apply(square, [1, 2, 3, 4])
print(results)  # [1, 4, 9, 16]

# Pass a built-in function
words = ["banana", "apple", "cherry"]
words.sort(key=len)  # sort by length
print(words)  # ['apple', 'banana', 'cherry']

4.6 Mutable Default Arguments

Default argument values are created once when the function is defined, not each time it is called. Using a mutable object (list, dict) as a default is a common bug:
# WRONG - the same list is shared across all calls
def append_to(item, lst=[]):
    lst.append(item)
    return lst

print(append_to(1))  # [1]
print(append_to(2))  # [1, 2]  - unexpected!

# CORRECT - use None as sentinel
def append_to(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

4.7 Example - All Together

# Functions - definitions and calling patterns.

def clamp(value: float, lo: float, hi: float) -> float:
    return max(lo, min(hi, value))

def stats(*numbers: float) -> tuple[float, float, float]:
    return min(numbers), max(numbers), sum(numbers) / len(numbers)

def repeat(func, n: int):
    for _ in range(n):
        func()

print(clamp(15, 0, 10))   # 10
print(clamp(-3, 0, 10))   # 0

lo, hi, avg = stats(4, 7, 2, 9, 1)
print(f"lo={lo}, hi={hi}, avg={avg:.1f}")

repeat(lambda: print("tick"), 3)
Expected output:
10
0
lo=1, hi=9, avg=4.6
tick
tick
tick

4.8 Exercise

Exercise
  • Write power(base, exponent=2) that raises base to exponent. Call it with one arg and with two.
  • Write summarize(*words) that returns a dict mapping each word to its length.
  • Write apply_twice(func, x) that applies func to x twice. Test it with a function that doubles a number.

4.9 Common Mistakes

Mutable default argument

Never use a list or dict as a default argument value. The same object is reused across all calls. Use None as the default and create the mutable object inside the function body.

Forgetting return

def add(a, b):
    a + b        # expression evaluated but result discarded

result = add(3, 4)
print(result)    # None
Without a return statement the function returns None.

Confusing *args in definition vs call

def total(*args):     # collects extra positional args into a tuple
    return sum(args)

nums = [1, 2, 3]
total(*nums)          # unpacks the list into positional args
total(nums)           # passes the whole list as one arg - wrong!

4.10 Key Terms

TermMeaning
defKeyword that introduces a function definition
returnExits the function and optionally provides a value to the caller
default argumentParameter with a fallback value used when the caller omits it
keyword argumentArgument passed by name at the call site
*argsCollects extra positional arguments into a tuple
**kwargsCollects extra keyword arguments into a dict
type hintOptional annotation (name: type) checked by mypy, not Python
first-class functionA function treated as a value: assignable, passable, returnable
lambdaAn anonymous single-expression function: lambda x: x * 2