Python Dataclasses · Examples
Object-Oriented Python

Python Dataclasses Examples

Short, runnable programs that show python dataclasses in action. Read the explanation, press Run, then change the code and try your own ideas. New to the topic? Start with the Python Dataclasses lesson.

1Hide or ignore a field with field()

field(repr=False) keeps a value out of the printed text, which is handy for secrets. field(compare=False) leaves a field out of ==, so two users count as equal even when only their visit counts differ.

Hide or ignore a field with field()
from dataclasses import dataclass, field

@dataclass
class User:
    name: str
    password: str = field(repr=False)
    visits: int = field(default=0, compare=False)

a = User("asha", "s3cret", 3)
b = User("asha", "s3cret", 99)
print(a)
print(a == b)
Expected outputUser(name='asha', visits=3)
True

2Validate and clean up in __post_init__

__post_init__ runs after the generated __init__, so it can tidy a value and refuse bad input before the object is used anywhere else.

Validate and clean up in __post_init__
from dataclasses import dataclass

@dataclass
class Email:
    address: str

    def __post_init__(self):
        self.address = self.address.strip().lower()
        if "@" not in self.address:
            raise ValueError(f"not an email address: {self.address!r}")

print(Email("  Asha@Example.COM "))
try:
    Email("asha.example.com")
except ValueError as err:
    print("Rejected:", err)
Expected outputEmail(address='asha@example.com')
Rejected: not an email address: 'asha.example.com'

3asdict() turns nested dataclasses into plain data

asdict() converts nested dataclasses into nested dictionaries, which json.dumps() can write. Going back needs a little rebuilding, because the inner dictionary is no longer an Address.

asdict() turns nested dataclasses into plain data
import json
from dataclasses import dataclass, asdict

@dataclass
class Address:
    city: str
    zip_code: str

@dataclass
class Customer:
    name: str
    address: Address

customer = Customer("Asha", Address("Pune", "411001"))
data = asdict(customer)
print(data)
print(json.dumps(data))
rebuilt = Customer(data["name"], Address(**data["address"]))
print(rebuilt == customer)
Expected output{'name': 'Asha', 'address': {'city': 'Pune', 'zip_code': '411001'}}
{"name": "Asha", "address": {"city": "Pune", "zip_code": "411001"}}
True

4One record, three ways: dict, plain class, dataclass

All three can hold a title and a page count. Only the dataclass gives you readable output and value-based equality without extra code, and unlike the dict it gives you attribute access.

One record, three ways: dict, plain class, dataclass
from dataclasses import dataclass

book_dict = {"title": "Dune", "pages": 412}

class BookPlain:
    def __init__(self, title, pages):
        self.title = title
        self.pages = pages

@dataclass
class Book:
    title: str
    pages: int

print(book_dict["title"], book_dict)
print(BookPlain("Dune", 412) == BookPlain("Dune", 412))
print(Book("Dune", 412) == Book("Dune", 412))
print(Book("Dune", 412))
Expected outputDune {'title': 'Dune', 'pages': 412}
False
True
Book(title='Dune', pages=412)

5A list of dataclasses: totals and the biggest item

Dataclass objects work anywhere other values do. Here a loop adds up expenses per category and max() with a key finds the largest one.

A list of dataclasses: totals and the biggest item
from dataclasses import dataclass

@dataclass
class Expense:
    label: str
    amount: float
    category: str = "misc"

expenses = [
    Expense("Coffee", 3.5, "food"),
    Expense("Train", 12.0, "travel"),
    Expense("Lunch", 9.25, "food"),
]
totals = {}
for item in expenses:
    totals[item.category] = totals.get(item.category, 0) + item.amount
print(totals)
print(max(expenses, key=lambda item: item.amount))
Expected output{'food': 12.75, 'travel': 12.0}
Expense(label='Train', amount=12.0, category='travel')

6kw_only: settings that must be named

With kw_only=True every field must be passed by name, so you can freely mix fields with and without defaults and nobody can mix up positional arguments.

kw_only: settings that must be named
from dataclasses import dataclass

@dataclass(kw_only=True)
class Config:
    host: str = "localhost"
    port: int = 8000
    debug: bool = False
    name: str

cfg = Config(name="demo", debug=True)
print(cfg)
try:
    Config("demo")
except TypeError:
    print("Config only accepts keyword arguments")
Expected outputConfig(host='localhost', port=8000, debug=True, name='demo')
Config only accepts keyword arguments

Practise next

Python Dataclasses exercises → Back to the lesson

Python Dictionaries examplesPython Classes and Objects examplesPython Dunder (Magic) Methods examplesWorking with JSON in Python examples