default_factory в dataclass: мощнее, чем кажется

Многие используют dataclass как удобный способ задать структуру с полями. Но редко кто по-настоящему раскрывает силу default_factory. А зря — он спасает от багов и даёт гибкость.

Когда нужно задать значение по умолчанию для поля в dataclass, логично тянуться к default=. Но если это изменяемый тип (например, список или словарь) — вас поджидает ловушка.

from dataclasses import dataclass, field

@dataclass
class User:
name: str
tags: list[str] = [] # ⚠️ опасно!


Все экземпляры User будут делить один и тот же список. То есть:

a = User("Alice")
b = User("Bob")
a.tags.append("admin")

print(b.tags) # ['admin'] 😱


Вместо этого используйте default_factory:

@dataclass
class User:
name: str
tags: list[str] = field(default_factory=list)


Теперь у каждого User будет свой список:

a = User("Alice")
b = User("Bob")
a.tags.append("admin")

print(b.tags) # []

Но default_factory не только про списки. Это отличный способ задать любое значение "по умолчанию", включая кастомную логику:

import uuid

@dataclass
class Session:
id: str = field(default_factory=lambda: str(uuid.uuid4()))
Или, например, значения из окружения:

import os

@dataclass
class Config:
debug: bool = field(default_factory=lambda: os.getenv("DEBUG") == "1")

Кстати, это ещё и отличное место для внедрения DI:

@dataclass
class Service:
client: "Client" = field(default_factory=create_default_client)

default_factory — это маленький хак, который позволяет сделать код чище и безопаснее, особенно когда работаешь с изменяемыми структурами или сложной инициализацией.

👉 @BookPython
Views: 505
Open in MAX Report an inaccuracy

Report an inaccuracy

Describe what needs fixing. If you have a source, add a link.

You are leaving datool.ru

The link leads to an external website. datool.ru is not responsible for its content — check the address before entering passwords or payment details.

Redirecting in 10 s

Go