ReviseAlgo Logo

Functions

Function Basics

Defining and calling functions, the foundation of Python programming

Interview: Fundamental concept tested in virtually all Python interviews

Last Updated: June 12, 2026 10 min read

Functions are the primary building block for organizing code in Python. They allow you to define reusable blocks of logic, improve code readability, and make debugging easier. Understanding function definition, invocation, and the execution model is essential for every Python developer.

Defining Functions

The def keyword creates a function object and binds it to a name:

  • Function name: Follows the same rules as variable names — use snake_case by convention
  • Parameters: Listed in parentheses — can include positional, keyword, default, args, and *kwargs
  • Docstring: Optional but recommended first line — describes what the function does
  • Body: Indented block of statements that executes when the function is called
  • Return: Optional return statement — if omitted, the function returns None implicitly

Function Execution Model

  • Definition time: def creates a function object — no code runs yet
  • Call time: Parentheses after the name trigger execution — func()
  • Local frame: Each call creates a new local scope with its own variables
  • Stack frames: Nested calls create a call stack — Python's default limit is ~1000 frames

Functions Are Objects

In Python, functions are first-class objects. You can assign them to variables, store them in lists, pass them as arguments, and set custom attributes on them. The def statement is essentially an assignment: it creates a function object and binds it to the function name.

Multiple Return Values

Python functions can return multiple values using tuples. This is commonly used for functions that compute related results:

  • Tuple packing: return a, b, c automatically packs into a tuple
  • Tuple unpacking: x, y, z = func() unpacks the returned tuple
  • Named tuples: Use collections.namedtuple for readable multi-value returns

Best Practices

  • Single responsibility: Each function should do one thing and do it well
  • Descriptive names: Use verb phrases like calculate_total() or validate_email()
  • Keep them short: Functions longer than ~20 lines should be broken into smaller functions
  • Avoid side effects: Prefer pure functions that don't modify external state

Common Pitfall: Mutable Default Arguments

Never use mutable objects (lists, dicts) as default parameter values. The default is created once at definition time and shared across all calls. Use None as default and create the mutable object inside the function body.

Use Cases

Breaking complex problems into smaller, testable units

Creating reusable utility functions (validation, formatting, conversion)

Implementing dispatch tables for command patterns and state machines

Building callback-based APIs and event handlers

Organizing code into modules with clear interfaces

Common Mistakes

Using mutable default arguments (lists, dicts) that persist between calls

Forgetting that functions without a return statement return None, not undefined

Writing functions that do too many things — violates single responsibility principle

Modifying global state inside functions — makes code hard to test and debug

Not adding docstrings — makes the codebase unmaintainable as it grows