Key Concepts
- Mutable Objects: Objects whose state can be modified after creation (e.g.,
list,dict,set, and custom class instances). - Default Argument Evaluation: In Python, default arguments are evaluated only once at the time the function is defined, not every time the function is called.
- Function Signature: The part of the function definition where parameters and their default values are declared.
The Problem: Mutable Default Arguments
The core issue is that when a mutable object (like an empty list []) is used as a default argument, Python creates that object once during the function definition. Subsequent calls to the function reuse the exact same object in memory.
Example of the Bug:
def create_player(name, inventory=[]):
inventory.append("starter weapon")
return {"name": name, "inventory": inventory}
When calling create_player("Alice") and then create_player("Bob"), both players share the same inventory list. Because the list is created at definition time, the "starter weapon" persists across calls, leading to unexpected data accumulation. This behavior applies equally to dictionaries, sets, and custom class instances.
The Solution: The "None" Pattern
To ensure that a new object is created for every function call, you must initialize the mutable object inside the function body.
Step-by-Step Implementation:
- Set the default to
None: Change the function signature to useNoneas the default value. - Check for
Noneinside the function: Use anifstatement to check if the argument isNone. - Initialize inside the function: Create the new list (or other mutable object) only if the check confirms the argument is
None.
Corrected Code:
def create_player(name, inventory=None):
if inventory is None:
inventory = []
inventory.append("starter weapon")
return {"name": name, "inventory": inventory}
Logic: By moving the initialization inside the function, the code executes at call time, ensuring every player gets a fresh, independent list.
Handling External Inputs Safely
If you need to pass an existing list as an argument but want to prevent the function from modifying the original object passed by the user, you should create a copy.
- Methodology: Use the
.copy()method (orlist()constructor) inside the function. - Why: This prevents "side effects" where the function accidentally modifies the data structure provided by the caller.
Refined Implementation:
def create_player(name, inventory=None):
if inventory is None:
inventory = []
else:
inventory = inventory.copy() # Prevents modifying the original list
inventory.append("starter weapon")
return {"name": name, "inventory": inventory}
Summary of Key Takeaways
- Avoid Mutable Defaults: Never use
[],{}, or custom objects as default arguments in Python function signatures. - Definition vs. Call Time: Remember that default arguments are bound at the moment the function is defined.
- Use
Noneas a Sentinel: The standard Pythonic way to handle optional mutable arguments is to default them toNoneand initialize them inside the function body. - Defensive Copying: If you expect users to pass their own lists into your function, use
.copy()to ensure your function operates on a local version of that data, preserving the integrity of the user's original object.
AI summaries can miss context or contain errors. Check important details against the original video.





