Today, I want to share a very common pitfall in Python—strange behavior when the default value of a class attribute is a mutable object (like a list).
A seemingly simple example
Let’s first look at a simple <span>Person</span>
class definition:
class Person:
def __init__(self, name:str, frients:list=[]):
self.name = name
self.frients = frients
def show_frients(self):
print(f"{self.name}, frients: {self.frients}")
It looks normal, right? When we create a <span>Person</span>
instance without providing the <span>frients</span>
parameter, it defaults to an empty list.
The strange phenomenon appears
Let’s create two <span>Person</span>
instances:
def main():
zhangsan = Person("zhangsan")
lisi = Person("lizi")
zhangsan.frients.append("x")
zhangsan.show_frients()
lisi.show_frients()
The output will surprise you:
zhangsan, frients: ['x']
lisi, frients: ['x']
What? We only added friend “x” for Zhang San, why does Li Si also automatically have this friend?
Why does this happen?
This phenomenon seems strange, but there is a reasonable explanation:
- Default parameters are evaluated at function definition time: Python’s function default parameters are created at the time of function definition (not at call time)
- All instances share the same default list: Since the
<span>frients</span>
parameter was not explicitly passed, both instances use the same default list object - Modifying the same list: When one instance modifies the list, all instances using the default list will be affected
How to avoid this pitfall?
Method 1: Explicitly pass an empty list
def main():
zhangsan = Person("zhangsan", [])
lisi = Person("lizi", [])
zhangsan.frients.append("x")
zhangsan.show_frients()
lisi.show_frients()
This method works, but you have to write an <span>[]</span>
every time you create an instance, which defeats the purpose of a default parameter.
Method 2: Modify the class definition (recommended)
A better approach is to avoid this issue in the class definition:
class Person:
def __init__(self, name:str, frients:list|None=None):
self.name = name
if frients is None:
self.frients = []
else:
self.frients = frients
In this way:
- The default parameter uses
<span>None</span>
(an immutable object) - A new list is created based on the situation in
<span>__init__</span>
- Each instance will get its own independent list
PyCharm’s helpful reminder
If you use PyCharm, it will intelligently identify this potential issue and give a warning:

Accepting its suggestion will automatically fix this issue.
Conclusion
This “trap” actually reflects a design choice in Python: default parameters are evaluated at function definition time. This is not a problem for immutable objects (like numbers, strings, tuples), but it can lead to unexpected behavior for mutable objects (like lists, dictionaries).
Remember this principle: Never use mutable objects as default parameters for functions/methods, use <span>None</span>
instead and initialize inside the function.
I hope this article helps you avoid this common pitfall for Python beginners!