Defining Reusable Functions

Functions are defined with def. Modules split code across files and are imported with import.

Good module structure helps maintenance and testing.

A function encapsulates a specific computation or behavior, making your codebase modular, readable, and DRY (Don't Repeat Yourself).

Function Parameters and Return Values

Python supports positional arguments, default keyword arguments, and arbitrary argument lists via *args and **kwargs:

def calculate_metrics(y_true, y_pred, verbose=False, **options):
    mse = sum((yt - yp) ** 2 for yt, yp in zip(y_true, y_pred)) / len(y_true)
    if verbose:
        print(f"Computed MSE: {mse:.4f}")
    return mse, options.get("metadata", {})

Scope Rules (LEGB)

Python resolves variable names using the LEGB rule in order:

  1. Local (L): Variables assigned inside the function body.
  2. Enclosing (E): Outer functions in nested closures.
  3. Global (G): Module-level variables defined at the file root.
  4. Built-in (B): Pre-assigned language keywords and functions like len, range.

Modules and Packages

Any Python source file (.py) acts as an importable module. When designing packages with multiple modules, include an __init__.py file to mark the directory as a Python package. Use if __name__ == "__main__": to ensure entry-point scripts only run when directly executed, rather than upon import.