0
0
Pythonprogramming~15 mins

Default arguments in Python - Deep Dive

Choose your learning style9 modes available
Overview - Default arguments
What is it?
Default arguments in Python are values given to function parameters that are used if no argument is provided when the function is called. This means you can call a function without specifying every parameter, and the function will use the default values instead. It helps make functions more flexible and easier to use. Default arguments are set in the function definition using an equals sign.
Why it matters
Without default arguments, every time you call a function, you must provide all the inputs, even if many calls use the same values repeatedly. This makes code longer, harder to read, and more error-prone. Default arguments save time and reduce mistakes by letting you skip common values, making your code cleaner and more user-friendly.
Where it fits
Before learning default arguments, you should understand how to define and call functions with parameters. After mastering default arguments, you can learn about keyword arguments, variable-length arguments, and advanced function features like decorators.
Mental Model
Core Idea
Default arguments are like preset choices in a form that fill in automatically unless you decide to change them.
Think of it like...
Imagine ordering coffee at a cafe where the barista asks if you want milk or sugar. If you don't say anything, they add the usual amount of milk and sugar by default. But if you want it different, you tell them. Default arguments work the same way in functions.
Function definition with default arguments:

  def function_name(param1, param2=default_value):
         │        │
         │        └─ default value used if param2 not given
         └─ required parameter

Function call examples:

  function_name(10)       # uses param2=default_value
  function_name(10, 20)   # uses param2=20
Build-Up - 7 Steps
1
FoundationUnderstanding function parameters
🤔
Concept: Functions can take inputs called parameters to work with different data.
In Python, you define a function with parameters inside parentheses. For example: def greet(name): print(f"Hello, {name}!") When you call greet('Alice'), it prints 'Hello, Alice!'. The parameter 'name' receives the value you pass.
Result
Calling greet('Alice') prints: Hello, Alice!
Knowing how parameters receive values is the base for understanding how default arguments provide fallback values.
2
FoundationCalling functions with arguments
🤔
Concept: You provide values called arguments when calling functions to replace parameters.
When you call a function, you must give values for all its parameters unless they have defaults. For example: def add(a, b): return a + b add(3, 4) # returns 7 If you forget an argument, Python gives an error.
Result
add(3, 4) returns 7; add(3) causes an error.
Understanding that missing arguments cause errors sets the stage for why default arguments are useful.
3
IntermediateSetting default argument values
🤔Before reading on: do you think default arguments can be any data type or only numbers? Commit to your answer.
Concept: You can assign default values to parameters in the function definition, which are used if no argument is given.
Syntax: def greet(name='friend'): print(f"Hello, {name}!") Calling greet() prints 'Hello, friend!' because 'name' defaults to 'friend'. You can still call greet('Alice') to override the default.
Result
greet() prints: Hello, friend! greet('Alice') prints: Hello, Alice!
Knowing defaults can be any type (string, number, list, etc.) makes functions flexible and easier to use.
4
IntermediateOrder of parameters with defaults
🤔Before reading on: should parameters with default values come before or after those without? Commit to your answer.
Concept: Parameters with default values must come after parameters without defaults in the function definition.
Correct: def func(a, b=2): return a + b Incorrect: def func(a=1, b): return a + b # causes SyntaxError This rule helps Python know which arguments are required and which are optional.
Result
Defining func(a=1, b) causes a SyntaxError.
Understanding parameter order prevents syntax errors and clarifies which arguments must be provided.
5
IntermediateUsing mutable default arguments safely
🤔Before reading on: do you think default lists or dictionaries are recreated fresh each call or shared across calls? Commit to your answer.
Concept: Mutable default arguments like lists or dictionaries are created once and shared across calls, which can cause unexpected behavior.
Example problem: def add_item(item, items=[]): items.append(item) return items Calling add_item('a') twice returns ['a'] then ['a', 'a'] because the same list is reused. Safe way: def add_item(item, items=None): if items is None: items = [] items.append(item) return items
Result
Using None as default avoids shared mutable state between calls.
Knowing this prevents bugs where data from one call leaks into another unexpectedly.
6
AdvancedCombining default and keyword arguments
🤔Before reading on: can you override default arguments by naming them explicitly when calling? Commit to your answer.
Concept: You can override default arguments by passing keyword arguments when calling the function.
Example: def greet(name='friend', greeting='Hello'): print(f"{greeting}, {name}!") greet() # Hello, friend! greet(name='Alice') # Hello, Alice! greet(greeting='Hi', name='Bob') # Hi, Bob!
Result
Keyword arguments let you change defaults in any order.
Understanding keyword arguments with defaults gives you precise control over function calls.
7
ExpertHow Python stores default argument values
🤔Before reading on: do you think default argument expressions are evaluated each call or once at function definition? Commit to your answer.
Concept: Default argument values are evaluated once when the function is defined, not each time it is called.
This means if you use an expression or mutable object as a default, it is created once and reused. Example: import time def f(t=time.time()): print(t) Calling f() multiple times prints the same timestamp because t was set once at definition. To get fresh values, use None and assign inside the function.
Result
Default values are fixed at definition time, not call time.
Knowing this explains subtle bugs and guides safer default argument usage.
Under the Hood
When Python reads a function definition, it evaluates all default argument expressions once and stores these values in a tuple attached to the function object. When the function is called without some arguments, Python fills those parameters with the stored default values. Mutable defaults are shared because the same object reference is reused. This behavior is part of Python's design to optimize performance and avoid re-evaluating defaults on every call.
Why designed this way?
Evaluating defaults once at definition improves efficiency by avoiding repeated computation. It also allows default values to be any object, including complex ones. However, this design requires care with mutable defaults to avoid unintended shared state. Alternatives like re-evaluating defaults each call would be slower and less predictable for some use cases.
Function Definition
┌─────────────────────────────┐
│ def func(a, b=default_val): │
└─────────────┬───────────────┘
              │
              ▼
  Default values evaluated once
              │
              ▼
  Stored in func.__defaults__ tuple
              │
              ▼
Function Call
┌─────────────────────────────┐
│ func(10)                    │
└─────────────┬───────────────┘
              │
              ▼
  Missing args replaced by defaults
              │
              ▼
  func uses stored default_val for b
Myth Busters - 4 Common Misconceptions
Quick: Do default argument values get recalculated every time the function is called? Commit to yes or no.
Common Belief:Default argument values are recalculated each time the function is called.
Tap to reveal reality
Reality:Default argument values are evaluated only once when the function is defined, not on every call.
Why it matters:This causes bugs when using mutable defaults or expressions that should change each call, leading to unexpected shared data or stale values.
Quick: Can you put parameters with default values before those without? Commit to yes or no.
Common Belief:You can place parameters with default values anywhere in the parameter list.
Tap to reveal reality
Reality:Parameters with default values must come after all parameters without defaults in the function definition.
Why it matters:Violating this rule causes syntax errors and confusion about which arguments are required.
Quick: If a default argument is a list, does each function call get a new list? Commit to yes or no.
Common Belief:Each call to a function with a list default argument gets a fresh new list.
Tap to reveal reality
Reality:All calls share the same list object created once at definition time.
Why it matters:This leads to data from one call leaking into others, causing hard-to-find bugs.
Quick: Can you override default arguments only by position, not by name? Commit to yes or no.
Common Belief:Default arguments can only be overridden by passing arguments in order, not by naming them.
Tap to reveal reality
Reality:You can override default arguments by naming them explicitly in the function call (keyword arguments).
Why it matters:Not knowing this limits flexibility and readability of function calls.
Expert Zone
1
Default arguments are stored in the function's __defaults__ attribute as a tuple, which can be inspected or modified dynamically.
2
Using None as a sentinel default value is a common Python idiom to avoid mutable default argument pitfalls.
3
Default argument expressions are evaluated in the defining scope, so they can capture variables from that scope, which can lead to subtle bugs if those variables change.
When NOT to use
Avoid using mutable objects like lists or dictionaries directly as default arguments; instead, use None and create new objects inside the function. For cases needing dynamic default values evaluated at call time, use None defaults or factory functions. If you need more complex parameter handling, consider using keyword-only arguments or decorators.
Production Patterns
In real-world code, default arguments are used to provide sensible defaults for configuration parameters, making APIs easier to use. Libraries often use None defaults combined with internal initialization to avoid mutable default issues. Keyword arguments with defaults improve code readability and maintainability by making function calls self-documenting.
Connections
Keyword arguments
Default arguments build on keyword arguments by providing fallback values when keywords are omitted.
Understanding default arguments clarifies how keyword arguments can be used flexibly to override defaults without positional order.
Immutable vs Mutable Data Structures
Default arguments expose the difference between immutable and mutable objects in Python function calls.
Knowing how default arguments behave with mutable objects deepens understanding of Python's data model and helps prevent shared state bugs.
Factory Design Pattern (Software Engineering)
Using None as a default and creating new objects inside functions is similar to the factory pattern that creates fresh instances on demand.
Recognizing this pattern helps write safer default argument code and connects function design to broader software engineering principles.
Common Pitfalls
#1Using a mutable object like a list as a default argument causes shared state across calls.
Wrong approach:def append_item(item, items=[]): items.append(item) return items
Correct approach:def append_item(item, items=None): if items is None: items = [] items.append(item) return items
Root cause:Misunderstanding that default argument objects are created once at function definition, not each call.
#2Placing parameters with default values before those without causes syntax errors.
Wrong approach:def func(a=1, b): return a + b
Correct approach:def func(a, b=1): return a + b
Root cause:Not knowing Python requires all non-default parameters to come before default ones.
#3Expecting default argument expressions to be evaluated at each call leads to stale or shared values.
Wrong approach:import time def log_time(t=time.time()): print(t)
Correct approach:import time def log_time(t=None): if t is None: t = time.time() print(t)
Root cause:Not realizing default arguments are evaluated once at function definition, not at call time.
Key Takeaways
Default arguments let you give parameters preset values used when no argument is provided, making functions easier to call.
Parameters with default values must come after those without to avoid syntax errors.
Default argument values are evaluated once when the function is defined, not each time it is called.
Using mutable objects as default arguments can cause shared state bugs; use None and create new objects inside the function instead.
Keyword arguments can override default values by naming parameters explicitly during function calls.