
class Book:
'''Object for tracking physical books in a collection.'''
def __init__(self, name: str, weight: float, shelf_id:int = 0):
self.name = name
self.weight = weight # in grams, for calculating shipping
self.shelf_id = shelf_id
def __repr__(self):
return(f"Book(name={self.name!r},
weight={self.weight!r}, shelf_id={self.shelf_id!r})")
The biggest headache here is that you must copy each of the arguments passed to __init__ to the object’s properties. This isn’t so bad if you’re only dealing with Book, but what if you have additional classes—say, a Bookshelf, Library, Warehouse, and so on? Plus, typing all that code by hand increases your chances of making a mistake.
Here’s the same class implemented as a Python dataclass:
from dataclasses import dataclass
@dataclass
class Book:
'''Object for tracking physical books in a collection.'''
name: str
weight: float
shelf_id: int = 0
When you specify properties, called fields, in a dataclass, the @dataclass decorator automatically generates all the code needed to initialize them. It also preserves the type information for each property, so if you use a linting too that checks type information, it will ensure that you’re supplying the right kinds of variables to the class constructor.