Python · 05/10 6 min
Classes and dataclasses
Instance vs class state, default_factory, equality and hashing, properties and repr.
Dataclasses save boilerplate
from dataclasses import dataclass, field
@dataclass
class Order:
id: int
items: list[str] = field(default_factory=list) # NOT `= []`
total: int = 0
You get __init__, __repr__ and __eq__ for free. A plain = [] default raises ValueError at class creation, which is a good thing.
Equality and hashing
@dataclasscompares field by field (__eq__), and by default makes instances unhashable (__hash__ = None): they can't go in a set or be dict keys.@dataclass(frozen=True)makes them immutable and hashable.- A plain class compares by identity unless you define
__eq__. If you define__eq__, define__hash__consistently (or not at all).
Properties keep invariants
class Account:
def __init__(self):
self._balance = 0
@property
def balance(self):
return self._balance # read-only from outside
def deposit(self, amount):
if amount <= 0:
raise ValueError("amount must be positive")
self._balance += amount
Class methods and static methods
class Spot:
@classmethod
def from_code(cls, code): return cls(*code.split("-")) # alternative constructor
@staticmethod
def is_valid(code): return "-" in code # no self or cls
Return copies of internal state
def history(self):
return list(self._history) # caller can't append to your internals
repr helps you debug
A good __repr__ turns <Order object at 0x10f…> into Order(id=3, total=900) in test failures. Dataclasses do it for you.
Practise it now
Next in Python
Collections for interviews