ReviseAlgo Logo

Functions

First-Class Functions

Functions as objects that can be assigned, passed, and stored

Interview: Core Python concept — underpins decorators, callbacks, and functional programming

Last Updated: June 12, 2026 8 min read

In Python, functions are first-class objects (citizens). This means they can be assigned to variables, stored in data structures, passed as arguments to other functions, and returned from functions — just like any other object (int, string, list). This is a foundational concept that enables decorators, callbacks, higher-order functions, and the entire functional programming paradigm in Python.

What First-Class Means

  • Assign to variables: my_func = some_function — creates a reference, not a copy
  • Pass as arguments: sorted(items, key=len) — len is passed as a function object
  • Return from functions: def make_adder(n): return lambda x: x + n
  • Store in data structures: Lists, dicts, sets can all contain function objects

Function Object Attributes

  • __name__: The function's name as a string
  • __doc__: The docstring (or None if not documented)
  • __module__: The module where the function was defined
  • __qualname__: Fully qualified name (includes class name for methods)
  • __annotations__: Type hints as a dictionary
  • __defaults__: Tuple of default parameter values
  • __closure__: Tuple of cells containing captured variables (for closures)

Custom Function Attributes

Since functions are objects, you can set custom attributes on them: func.count = 0. This is useful for stateful functions without needing a class, but prefer closures or classes for complex state management.

Dispatch Tables

One of the most practical uses of first-class functions is building dispatch tables — dictionaries that map keys to functions. This replaces long if/elif chains with a clean, extensible lookup:

  • Dict of functions: {op: function} — look up and call the right function
  • Command pattern: Map command names to handler functions
  • Strategy pattern: Swap algorithms at runtime by passing different functions

Use Cases

Building dispatch tables and command patterns to replace long if/elif chains

Implementing callback-based APIs and event-driven architectures

Dependency injection — passing functions to make code testable and flexible

Storing handler functions in registries for plugin systems

Strategy pattern — swapping algorithms at runtime without code changes

Common Mistakes

Calling the function instead of passing it — func() executes, func passes the object

Using custom function attributes instead of closures/classes for complex state

Not realizing that assigning a function doesn't copy it — both names reference the same object

Forgetting that lambda functions have __name__ = "<lambda>" — hard to debug in dispatch tables

Overusing dispatch tables when a simple if/elif is clearer for 2-3 conditions