@dataclass

Dekorator, który na podstawie pól z adnotacjami typów generuje __init__, __repr__ i __eq__ klasy przechowującej dane.

Zwraca
Tę samą klasę uzupełnioną o wygenerowane metody.
Na tej stronie

Przykład

#
Python
from dataclasses import dataclass, field

@dataclass
class Student:
    name: str
    world: int
    points: int = 0
    badges: list[str] = field(default_factory=list)

ania = Student("Ania", 7)
ania.points += 40
ania.badges.append("Start")

print(ania)
print(ania == Student("Ania", 7, 40, ["Start"]))
print(Student("Kuba", 2))
Wynikzapisany wynik, możesz go sprawdzić
Student(name='Ania', world=7, points=40, badges=['Start'])
True
Student(name='Kuba', world=2, points=0, badges=[])

Definicja i zastosowanie

#

Dekorator @dataclass z modułu dataclasses usuwa z klas przechowujących dane powtarzalny kod. Wystarczy wypisać pola z adnotacjami typów (name: str), a dekorator wygeneruje __init__ z parametrami w tej samej kolejności, czytelny __repr__ oraz __eq__, który porównuje obiekty pole po polu.

Pola mogą mieć wartości domyślne (points: int = 0), ale pola bez wartości domyślnej muszą stać przed nimi. Listę, słownik czy inny zmienny obiekt jako wartość domyślną podaje się przez field(default_factory=list), dzięki czemu każdy obiekt dostaje własną kopię. Dodatkowe kroki po utworzeniu obiektu, np. walidację albo wyliczenie pomocniczego pola, umieść w metodzie __post_init__.

Parametry dekoratora zmieniają zachowanie klasy, np. frozen=True blokuje zmiany pól, a order=True dodaje porównania < i >. Funkcja asdict() zamienia obiekt na słownik, np. do zapisu w JSON, a replace() tworzy kopię ze zmienionymi polami. Adnotacje typów nie są sprawdzane w czasie działania programu, służą edytorom i narzędziom takim jak mypy.

Składnia

#
Składnia
from dataclasses import dataclass, field

@dataclass
class Nazwa:
    pole: typ
    pole_z_domyslna: typ = wartosc
    lista: list[typ] = field(default_factory=list)

@dataclass(frozen=True, order=True)
class Inna:
    ...

Parametry

#
  • frozen

    bool, domyślnie False

    Gdy True, zmiana pola zgłasza FrozenInstanceError, a obiekty mogą być kluczami słowników i elementami zbiorów.
  • order

    bool, domyślnie False

    Dodaje operatory <, <=, > i >=, które porównują pola po kolei, tak jak krotki.
  • slots

    bool, domyślnie False

    Tworzy klasę z __slots__: obiekty zajmują mniej pamięci, a przypisanie do nieistniejącego pola zgłasza błąd.
  • kw_only

    bool, domyślnie False

    Wymusza podawanie wszystkich pól po nazwie przy tworzeniu obiektu.

Więcej przykładów

#
Niezmienne obiekty z sortowaniem
Python
from dataclasses import dataclass, field

@dataclass(frozen=True, order=True)
class Result:
    points: int
    name: str = field(compare=False)

results = [Result(78, "Kuba"), Result(92, "Ania"), Result(85, "Ola")]
print([r.name for r in sorted(results, reverse=True)])

best = max(results)
try:
    best.points = 100
except AttributeError as error:
    print(type(error).__name__, error)
Wynikzapisany wynik, możesz go sprawdzić
['Ania', 'Ola', 'Kuba']
FrozenInstanceError cannot assign to field 'points'

field(compare=False) wyłącza pole z porównań, więc wyniki są sortowane tylko po punktach.

Walidacja i pole wyliczane w __post_init__
Python
from dataclasses import dataclass, field

@dataclass
class Exercise:
    number: str
    exp: int
    world: int = field(init=False)

    def __post_init__(self):
        if self.exp < 0:
            raise ValueError("EXP nie może być ujemne")
        self.world = int(self.number.split("_")[0])

task = Exercise("7_3", 15)
print(task.world)
print(task)
Wynikzapisany wynik, możesz go sprawdzić
7
Exercise(number='7_3', exp=15, world=7)
asdict() i replace()
Python
import json
from dataclasses import asdict, dataclass, replace

@dataclass
class Course:
    title: str
    modules: int
    premium: bool = False

python = Course("Python", 12)
advanced = replace(python, title="Python zaawansowany", premium=True)

print(advanced)
print(asdict(python))
print(json.dumps(asdict(advanced), ensure_ascii=False))
Wynikzapisany wynik, możesz go sprawdzić
Course(title='Python zaawansowany', modules=12, premium=True)
{'title': 'Python', 'modules': 12, 'premium': False}
{"title": "Python zaawansowany", "modules": 12, "premium": true}

Dobre praktyki

#
  • Pola ze zmiennymi wartościami domyślnymi twórz przez field(default_factory=list). Zapis badges: list = [] zgłosi ValueError już przy definicji klasy.
  • Typy w adnotacjach nie są sprawdzane, więc Student(name=123, world="siedem") utworzy obiekt bez błędu. Do walidacji użyj __post_init__ albo biblioteki pydantic.
  • Obiekty z frozen=True można bezpiecznie współdzielić między częściami programu, bo nikt ich przypadkiem nie zmieni.

Powiązane hasła

#

Widzisz błąd albo brakuje przykładu? Napisz do nas.