Defaults and default_factory

dataclasses · Essentials · 8 min

Getting defaults wrong either raises at class creation or shares one list between all instances.

Fields can have default values: retries: int = 3. Fields with defaults become optional constructor parameters, and they must come after fields without defaults, just like function parameters. Otherwise you get TypeError: non-default argument 'b' follows default argument when the class is created.

Mutable defaults are a classic Python trap: a default list in a function signature is shared across calls. Dataclasses protect you: tags: list[str] = [] raises ValueError: mutable default <class 'list'> for field tags is not allowed: use default_factory. The check rejects any default that is unhashable, which covers list, dict and set.

The fix is field(default_factory=...), a zero-argument callable called for each new instance:

tags: list[str] = field(default_factory=list)
created: datetime = field(default_factory=datetime.now)

Any callable works: list, dict, a lambda, or a function returning a fresh default config.

Default values are also stored as class attributes, so Config.retries is 3. Fields using default_factory have no class attribute.

Keyword-only fields (a later lesson) relax the ordering rule.

Example

from dataclasses import dataclass, field
from datetime import datetime

@dataclass
class Task:
    title: str
    priority: int = 3
    tags: list[str] = field(default_factory=list)
    created: datetime = field(default_factory=datetime.now)

a, b = Task("write docs"), Task("fix bug", priority=1)
a.tags.append("docs")
print(a.tags, b.tags)              # ['docs'] []   (separate lists)
print(b.priority, Task.priority)   # 1 3

try:
    @dataclass
    class Bad:
        items: list[int] = []
except ValueError as e:
    print(e)   # mutable default <class 'list'> for field items is not allowed: use default_factory

Remember

  • Fields with defaults must follow fields without
  • Mutable defaults like [] are rejected
  • field(default_factory=list) creates a fresh value per instance

Watch out for

  • Using a mutable custom object as a default; it is shared unless it is unhashable and rejected.

Check yourself

  1. Why does tags: list[str] = [] raise ValueError in a dataclass?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/dataclasses.html#mutable-default-values