Python Default Parameter Pitfall: Shared Mutable State

🐍 An Interesting (and Sneaky) Python Bug I Ran Into I’ve been working through Fluent Python recently, and one part, "Mutable Types as Parameter Defaults: Bad Idea", reminded me of a classic pitfall that even experienced developers stumble into: using mutable objects as default parameters. It looks innocent enough: def add_item(item, container=[]): container.append(item) return container But here’s the twist: Python evaluates default parameter values only once—when the function is defined, not each time it’s called. So instead of getting a fresh list every call, you get shared state: add_item(1) # [1] add_item(2) # [1, 2] # surprise! This behavior is intentional, but it can lead to subtle, head‑scratching bugs if you’re not expecting it. The safe pattern is: def add_item(item, container=None): if container is None: container = [] container.append(item) return container Why This Bug Doesn’t Happen in C# or C++ One thing I appreciate about strongly typed languages is how their design choices prevent entire categories of bugs. C# C# requires that default parameters be compile‑time constants: numbers, strings, enums, null You cannot use a mutable object as a default: void Foo(List<int> xs = new List<int>()); // ❌ compile error This rule completely eliminates Python’s shared‑mutable‑default issue. C++ C++ also avoids the problem, but for a different reason. Default arguments in C++ are compile‑time expressions, and they are substituted at the call site, not stored in the function object. This is allowed: void foo(const std::vector<int>& v = std::vector<int>()); // ✔ OK But the key detail is: a new temporary object is created every time the function is called. So there’s no shared state, and no Python‑style surprise. Takeaway Python’s flexibility is powerful, but it comes with sharp edges. C# and C++ take a stricter, compile‑time‑driven approach that prevents this entire class of bugs. If you’re writing Python APIs or utilities, it’s worth double‑checking your default parameters. A tiny detail can lead to some very unexpected behavior.

To view or add a comment, sign in

Explore content categories