Data Classes

Master the powerful @dataclass decorator and advanced class patterns that professional engineers use when building large Python systems. Learn to create efficient, immutable, and production-ready data models used in APIs, ML pipelines, and enterprise architectures.

Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn

This comprehensive lesson teaches you everything professional engineers use when building large Python systems:

🔥 1. Why Dataclasses Exist

Before Python 3.7, writing classes was repetitive:

This is why dataclasses became standard in production systems.

⚙️ 2. Creating Dataclasses

🧠 3. Default Values

default_factory is critical for safe dataclass design.

🧩 4. Post-Init Processing

Sometimes you need validation or computed attributes.

⚡ 5. Making Dataclasses Immutable (Frozen Models)

Frozen dataclasses behave like lightweight value objects (DDD concept).

🔄 6. Ordering & Comparison

📦 7. Dataclasses + Type Hints (Power Combo)

Dataclasses work perfectly with typing tools like MyPy, Pyright, and IDE autocomplete.

Your entire codebase becomes clearer, safer, faster to maintain.

🧬 8. Slots Dataclasses (Big Performance Boost)

Python normally stores instance values in a dictionary ( __dict__ ).

Slots remove the dict and store variables in fixed memory locations.

🔥 9. Inheritance With Dataclasses

🧱 10. Frozen + Slots (Enterprise Pattern)

📊 11. Dataclasses vs NamedTuple vs Pydantic

A backend system often uses all three, depending on needs.

🎮 12. Real Project Example — Inventory Item

🧪 13. Real Project Example — API Request Model

This mirrors real FastAPI/Pydantic usage but with pure dataclasses.

🎯 14. Real Project Example — ML Config

Dataclasses are used massively in ML research tools like:

🔥 15. Field Customization (metadata, repr, compare, init control)

Every field in a dataclass can be finely controlled:

Metadata example (used in FastAPI/Pydantic-style schemas):

This allows libraries to generate automatic documentation.

⚙️ 16. Keyword-Only & Positional-Only Fields

Python supports forcing fields to be keyword-only:

🧠 17. Dataclass Factories (Dynamic Dataclass Creation)

🔄 18. Inheritance Pitfalls & Solutions

PROBLEM 1: Parent fields come before child fields

PROBLEM 2: Parent has default values but child doesn't

🧱 19. Mixing Dataclasses With OOP

Dataclasses are not a replacement for OOP — they enhance it.

📦 20. Dataclasses + Abstract Base Classes (ABC)

This pattern powers plugin systems, physics engines, rendering systems, etc.

🧩 21. Immutable Value Objects (Enterprise Architecture)

In Domain-Driven Design (DDD), models like Money, Weight, Coordinates, Identity, Version should be immutable.

🧬 22. Dataclasses for Validation-Like Behavior

While not as powerful as Pydantic, you can build lightweight validators:

📚 23. Dataclasses as DTOs (Data Transfer Objects)

Frameworks like Django, Flask, FastAPI use DTO patterns everywhere.

🚀 24. Dataclasses + JSON Serialization

🧵 25. Frozen Dataclasses + Hashing

🕹 26. Advanced Pattern — Rich Models With Methods + Validation

Example combining: slots, frozen, methods, computed properties

🎮 27. Real Project Example — E-Commerce Order Model

🔥 28. Slots + Dataclasses — High-Performance Python

Adding slots=True dramatically reduces memory usage and speeds attribute access.

⚙️ 29. Combining Frozen + Slots (Ultimate Efficiency)

A frozen & slotted dataclass is: immutable, hashable, extremely memory efficient, and extremely fast.

🧠 30. Overriding post_init in Frozen Dataclasses

Frozen normally blocks all changes — but you can bypass immutability inside __post_init__ :

Used by: FastAPI, Pydantic, ORMs, Serializers

Practice quiz

What does the @dataclass decorator auto-generate?

  • Only __init__
  • Database tables
  • __init__, __repr__, and __eq__
  • Type checks at runtime

Answer: __init__, __repr__, and __eq__. @dataclass removes boilerplate by auto-generating __init__, __repr__, and __eq__.

Why must you avoid a mutable default like tags: list = []?

  • All instances would share the same list
  • It is a syntax error
  • Lists cannot be defaults
  • It makes the class frozen

Answer: All instances would share the same list. A bare mutable default is shared across all instances; use field(default_factory=list) instead.

What is the correct way to give a dataclass field a safe mutable default?

field(default_factory=list) creates a fresh list for each instance.

Which method runs validation or computed attributes right after a dataclass is created?

  • __init__
  • __post_init__
  • __new__
  • __setup__

Answer: __post_init__. __post_init__ runs after the auto-generated __init__ for validation or computed fields.

What does @dataclass(frozen=True) give you?

  • Immutable, hashable instances usable as dict keys
  • Faster attribute access only
  • Automatic slots
  • Mutable fields

Answer: Immutable, hashable instances usable as dict keys. Frozen dataclasses are immutable and hashable, so they can be dict keys or set elements.

What does @dataclass(order=True) add?

  • A frozen flag
  • JSON serialization
  • Comparison methods <, <=, >, >=
  • Slots

Answer: Comparison methods <, <=, >, >=. order=True auto-generates the ordering comparison methods.

What is the main benefit of @dataclass(slots=True)?

  • Adds validation
  • Lower memory use and faster attribute access
  • Makes the class frozen
  • Enables inheritance

Answer: Lower memory use and faster attribute access. slots removes the per-instance __dict__, reducing memory and speeding attribute access.

What does dataclasses.asdict(obj) return for a dataclass?

  • A JSON string
  • A tuple
  • A copy of the object
  • A dict of its fields (recursively for nested dataclasses)

Answer: A dict of its fields (recursively for nested dataclasses). asdict() converts the dataclass (and any nested dataclasses) into a plain dict.

Inside a frozen dataclass's __post_init__, how can you still normalize a field?

  • self.email = value
  • object.__setattr__(self, 'email', value)
  • frozen=False
  • You cannot at all

Answer: object.__setattr__(self, 'email', value). object.__setattr__ bypasses the frozen restriction during initialization only.

Two instances User('Sam', 30) and User('Sam', 30) of a basic @dataclass compare as...

  • Not equal
  • An error
  • Equal
  • Equal only with frozen=True

Answer: Equal. The auto-generated __eq__ compares by field values, so they are equal.