February 21, 2025

About

You might be surprised to see this code.

def f_bug(arg, result=[]):
    result.append(arg)
    print(result)

f_bug('a')  # ['a']
f_bug('b')  # ['a', 'b']

If you are Python beginner, you would expect the response [‘b’] from second f_bug function calling. But it is NOT. why does it happen?

Why does it happen?

The reason is that default variable (which is argument,) is initialized when the function is defined. So, once it is initialized to set a default value, it will be changed afterwards. Therefore it, it would make engineers confused I believe. The good strategy here is not to use mutable variables such as list, dict set as default, and to use immutable variables such as values (int, float) and tuple so that the variable not to call repeatedly.

Other Strategy?

Even so, you must hope to use objects from flexible classes like BaseModel in Pydantic.

from pydantic import BaseModel

class User(BaseModel):
    name: str
    tags: list = []  # Mutable Default Object

user1 = User(name="Kohei")
user2 = User(name="Kevin")

user1.tags.append("admin")
print(user1.tags)  # ['admin']
print(user2.tags)  # ['admin'] Expected Behavior: The changes made by user1 will be affected

default_factory

As like you see above, the same error happens even when you simply use BaseModel. The solution here is to use default_factory, then it will be solved.

from pydantic import BaseModel, Field

class User(BaseModel):
    name: str
    tags: list = Field(default_factory=list)  # Create a list every initialization

user1 = User(name="Kohei")
user2 = User(name="Tanaka")

user1.tags.append("admin")
print(user1.tags)  # ['admin']
print(user2.tags)  # [] Expected Behavior