Dataclasses
About 18 minutes
Why this matters
Many classes are mostly a bag of fields: __init__ copies arguments onto self, __repr__ prints them, __eq__ compares them. A dataclass writes all of that for you from a short list of fields.
The idea
from dataclasses import dataclass, field
@dataclass
class Player:
name: str
score: int = 0 # a default value
items: list = field(default_factory=list) # a NEW list for each object
p = Player("Ada")
print(p) # Player(name='Ada', score=0, items=[])
print(p == Player("Ada")) # True: compares all fields
Useful options:
@dataclass(frozen=True): instances cannot be changed after creation, and can be dictionary keys.@dataclass(order=True): adds<,>,<=,>=using the fields in order.field(compare=False): leave a field out of comparisons.__post_init__(self): a method run right after the generated__init__, handy for validation.
The type hints are required, but Python does not enforce them.
Try it
Make a Player dataclass and print one. Then add frozen=True and try p.score = 5. What error do you get?
Your turn
Write three dataclasses:
Productwith fieldsname,priceandtags(a list, new for each product, empty by default). A negative price raisesValueError("price cannot be negative"). Add a methodprice_with_tax(rate)returning the price plus tax, rounded to 2 decimals.Coordinatewithlatandlon, frozen, so it can be used as a dictionary key.Taskwithpriority(an int) andtitle(a string that is not used for comparing), ordered so thatsorted()puts the lowest priority number first.
Recap
@dataclassgenerates__init__,__repr__and__eq__from the annotated fields.- Use
field(default_factory=list)for mutable defaults. frozen=Trueandorder=Trueadd immutability and sorting.
Common mistakes
tags: list = []raisesValueError: mutable default <class 'list'> for field tags is not allowed: use default_factory.- A field with a default before one without:
TypeError: non-default argument 'x' follows default argument. - Forgetting the type hint, so the name is a plain class attribute and not a field.