Topic 03

When a Class Helps and When a Dict Is Enough

Hands-on

Once you know classes, it is tempting to make everything one. Often a dictionary, or a plain function, is simpler and better, and experienced programmers reach for classes less often than beginners expect. This page gives an honest rule of thumb for choosing, so classes appear where they earn their place.

Think of a shoebox, a labelled filing folder and a locked cash box. Each is the right container for something, and you would not keep old receipts in the cash box. The containers in a program deserve the same judgment.

A Dictionary Is Enough When

The data is passed along without rules of its own, or it is loaded from JSON and saved back to JSON, or it only ever lives for a few lines. The rows from csv.DictReader in Chapter 7 were dictionaries, and that was exactly right: they were read, converted and totalled, and nothing more.

A Dataclass Helps When

The same shape of record appears in several parts of a program, and you want a mistake in it to be caught. The difference shows at the moment a record is created. Misspell a key in a dictionary and it is simply accepted as a new key; nothing complains, and the mistake surfaces much later, if at all. Misspell a field when creating a dataclass object and Python refuses at once, and Python 3.15 even suggests the right name.

typo.py
from dataclasses import dataclass


@dataclass
class Book:
    title: str
    author: str
    pages: int


record = {"title": "Dune", "author": "Frank Herbert", "pages": 412}
record["titel"] = "Dune Messiah"
print(record)

Book(titel="Dune", author="Frank Herbert", pages=412)
Output
{'title': 'Dune', 'author': 'Frank Herbert', 'pages': 412, 'titel': 'Dune Messiah'}
Traceback (most recent call last):
  File "/Users/you/python-course/typo.py", line 15, in <module>
    Book(titel="Dune", author="Frank Herbert", pages=412)
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Book.__init__() got an unexpected keyword argument 'titel'. Did you mean 'title'?

To be fair to dictionaries, the protection has limits. Assigning a misspelled field to an existing dataclass object, as in book.titel = "...", with title misspelled, is also accepted silently, unless the class is declared with an option called slots, which is beyond this book. The dataclass catches mistakes where records are made, which is where most of them happen.

A Class with Methods Helps When

The data comes with rules that must always hold. A bank balance that must never go below zero is the classic example: put the rule inside a withdraw method, and no part of the program can forget it. When the rules live in one place, next to the data they protect, they cannot drift apart.

A Function Is Enough When

There is behaviour but no lasting data. A conversion, a calculation, a check: calculate_tip(bill, percent) does not need to be a class. A class with one method and nothing to remember is usually a function that got dressed up.

Converting Between Them

The two worlds meet easily. The asdict function from the dataclasses module turns a dataclass object into a dictionary, ready for JSON. Going the other way, two stars in front of a dictionary spread its keys out as keyword arguments, so Book(**data) builds a Book from a dictionary with matching keys, and still catches a misspelled one.

convert.py
from dataclasses import asdict, dataclass


@dataclass
class Book:
    title: str
    author: str
    pages: int


dune = Book("Dune", "Frank Herbert", 412)
data = asdict(dune)
print(data)
print(Book(**data))
Output
{'title': 'Dune', 'author': 'Frank Herbert', 'pages': 412}
Book(title='Dune', author='Frank Herbert', pages=412)
Choosing a container for your data
Does the data have rules that must always hold?→a class with methods
Is the same shape used across the program?→a dataclass
Otherwise→a dictionary
Common Confusions
  • "Professional code uses classes for everything." Good code uses the simplest structure that does the job. Many excellent programs have few classes.
  • "Dictionaries are the beginner's option." They are the right option for a great deal of data, at every level of experience.
  • "A dataclass catches every misspelled field." It catches them when a record is created. Assigning a misspelled field later is accepted unless the class uses slots.
  • "Classes make programs faster." They make some programs clearer. Speed is not the reason to use one.
Why It Matters
  • Choosing the simplest structure keeps programs small and easy to read, which matters more than any single clever design.
  • The same judgment applies in every language that has classes, which is almost all of them.

Knowledge Check

What happens when you add the key "titel" to a dictionary by mistake?

  • It is accepted silently as a new key
  • Python raises a KeyError straight away
  • Python corrects it to title automatically
  • The dictionary refuses keys it has not seen

What happens with Book(titel="Dune", ...) for a dataclass with a title field?

  • The misspelled field is stored alongside the others
  • A TypeError, which in 3.15 suggests the name title
  • The title field is quietly left as None
  • Python renames titel to title for you and carries on

When is a class with methods the right choice?

  • Whenever the program is longer than a hundred lines
  • Whenever data is loaded from a JSON file
  • When the data has rules that must always hold
  • Whenever a function needs more than two parameters

What does asdict(book) give?

  • A JSON string, ready to be written to a file
  • A copy of the Book object with the same fields
  • A list of the book's field names, in order
  • A dictionary of the book's fields and values

You got correct