Skip to content

Functions

Create reusable blocks of code with Python functions.

Basic Functions

def greet(name: str) -> str:
    """Return a greeting message."""
    return f"Hello, {name}!"

# Call the function
message = greet("Alice")
print(message)  # Hello, Alice!

Parameters

Default Parameters

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

greet("Alice")              # Hello, Alice!
greet("Bob", "Hi")          # Hi, Bob!

*args and **kwargs

def sum_all(*args: int) -> int:
    """Sum all arguments."""
    return sum(args)

sum_all(1, 2, 3, 4, 5)  # 15

def print_info(**kwargs: str) -> None:
    """Print keyword arguments."""
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", city="NYC")

Keyword-Only Arguments

def create_user(name: str, *, age: int, email: str) -> dict:
    """Age and email must be keyword arguments."""
    return {"name": name, "age": age, "email": email}

# Must use keywords
user = create_user("Alice", age=30, email="alice@example.com")

Return Values

Multiple Returns

def get_min_max(numbers: list[int]) -> tuple[int, int]:
    """Return min and max values."""
    return min(numbers), max(numbers)

minimum, maximum = get_min_max([1, 5, 3, 9, 2])

Early Returns

def find_item(items: list[str], target: str) -> int | None:
    """Return index of target or None."""
    for i, item in enumerate(items):
        if item == target:
            return i
    return None

Lambda Functions

# Anonymous function
square = lambda x: x ** 2
square(5)  # 25

# Common with sorted
pairs = [(1, 'one'), (3, 'three'), (2, 'two')]
sorted(pairs, key=lambda x: x[0])
# [(1, 'one'), (2, 'two'), (3, 'three')]

# With filter
numbers = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, numbers))
# [2, 4, 6]

# With map
squares = list(map(lambda x: x ** 2, numbers))
# [1, 4, 9, 16, 25, 36]

Decorators

def timer(func):
    """Measure function execution time."""
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} took {end - start:.4f}s")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(1)
    return "Done!"

Generators

def countdown(n: int):
    """Generate countdown sequence."""
    while n > 0:
        yield n
        n -= 1

for num in countdown(5):
    print(num)  # 5, 4, 3, 2, 1

Error Handling

def safe_divide(a: int, b: int) -> float | None:
    """Safely divide two numbers."""
    try:
        return a / b
    except ZeroDivisionError:
        print("Cannot divide by zero!")
        return None
    finally:
        print("Division attempt completed.")

safe_divide(10, 2)   # 5.0
safe_divide(10, 0)   # None, with error message

Type Hints

from typing import TypeVar, Generic, Sequence

T = TypeVar('T')

def first_item(items: Sequence[T]) -> T | None:
    """Return first item or None."""
    return items[0] if items else None

# Generic class
class Stack(Generic[T]):
    def __init__(self) -> None:
        self._items: list[T] = []

    def push(self, item: T) -> None:
        self._items.append(item)

    def pop(self) -> T | None:
        return self._items.pop() if self._items else None

Practice Files

  • build/foundations/03-functions/basics.py
  • build/foundations/03-functions/decorators.py
  • build/foundations/03-functions/generators.py

Next Phase

Ready for Data Structures!