Functions
Parameters and Arguments
Positional, keyword, default, and keyword-only arguments
Interview: Critical for interviews — mutable defaults is one of the most asked Python questions
Python provides an incredibly flexible parameter system. Understanding the different parameter types, their ordering rules, and how arguments are matched to parameters is essential for writing clean, Pythonic functions and is a frequent interview topic.
Parameter Types
- Positional parameters: Required, matched by position —
def func(a, b) - Default parameters: Optional with default values —
def func(a, b=10) - Keyword-only parameters: Must be passed by name (after
*) —def func(a, *, b) - Positional-only parameters: Cannot be passed by keyword (before
/, Python 3.8+) —def func(a, /, b) - args: Collects extra positional arguments into a tuple
- *kwargs: Collects extra keyword arguments into a dict
Parameter Ordering Rules
Parameters must follow this exact order:
- Positional-only (before
/) - Regular positional/keyword
*args- Keyword-only (between
*argsand**kwargs) **kwargs
The Mutable Default Argument Trap
This is the #1 Python interview question about parameters. Default values are evaluated once at function definition time, not at each call. Using def func(lst=[]) means ALL calls share the same list. Always use def func(lst=None) and create the mutable object inside the function.
Positional-Only and Keyword-Only
- Positional-only (/): Forces callers to pass args by position — used in built-in functions like
len(obj, /)to prevent keyword usage - Keyword-only (): Forces callers to use named args — improves readability for boolean flags and configuration options
- Bare : You can use
*without a name to separate positional from keyword-only parameters
Argument Unpacking
- operator: Unpacks a list/tuple into positional arguments —
func(*[1, 2, 3]) - * operator: Unpacks a dict into keyword arguments —
func(**{"a": 1, "b": 2}) - Combined:
func(*args, **kwargs)forwards all arguments to another function
Pro Tip: Force Keyword Arguments
Use * to force callers to use keyword arguments for clarity: def connect(host, port, *, timeout=30, retries=3). This prevents connect("localhost", 5432, 60, 5) where it's unclear what 60 and 5 mean.
Use Cases
Designing flexible APIs with optional and keyword-only parameters
Building decorator wrappers that forward arbitrary arguments with `*args`, `**kwargs`
Creating configuration functions where keyword-only args improve readability
Implementing factory functions with sensible defaults
Writing generic wrapper functions in frameworks and middleware
Common Mistakes
Using mutable objects (list, dict) as default parameter values — shared across calls
Putting default parameters before non-default parameters — causes SyntaxError
Forgetting the ordering rule: positional-only → normal → `*args` → keyword-only → `**kwargs`
Not using keyword-only (*) for boolean flags — makes calls like func("x", True, False) unreadable
Confusing `*args` (collects into tuple) with `**kwargs` (collects into dict)