Creating custom objects with unique properties and methods using classes in Python is a headache, as you have to write inessentially complex boilerplate code to integrate functions such as comparison operators or define class instances.
Table of Contents
Luckily, there exists a better way to create custom objects in Python; dataclasses. Introduced in Python 3.7, they provide a quick fix to create new classes and save developers from writing lines of complex codes for basic operations.
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})")
Above is the traditional way to create classes in Python and it is evident how needlessly complex it is. Ironically, in it, __init__ cause the most stress as the method requires copying every argument passed through __init__ to the object’s properties.
In the example above, the process doesn’t look so messy. However, repeat the same for its parent and child classes times infinity, and you will know. The act doesn’t only take time but also up the odds of error as manually typing repetitive codes is no child’s play.
Now let’s deploy the same class the new way by using Python dataclasses.
from dataclasses import dataclass @dataclass class Book: '''Object for tracking physical books in a collection.''' name: str weight: float shelf_id: int = 0
The difference is clear. Python dataclasses perform the same in lesser code, as properties or fields in a dataclass generate the missing code automatically. More so, it also preserves the information for later use and enables us to make the most use of code linter like mypy.
In addition, Python dataclasses also auto-create codes for dunder methods. The feature is on display in two Python dataclass examples above. In the first, we had to define __repr__, while in the second, the @dataclass decorator suffice.
As the final product is functionally identical, it is a no-brainer to use dataclasses over classes for ease of use.
In Python dataclasses, the default specifications work to create basic functional classes more often than not. However, sometimes, you may have to tweak how the fields get processed. Luckily, the process is still not as arduous as creating classes old-style. Here’s an example below:
from dataclasses import dataclass, field, InitVar from typing import List @dataclass class Book: '''Object for tracking physical books in a collection.''' name: str condition: str = field(compare=False) weight: float = field(default=0.0, repr=False) shelf_id: int = 0 chapters: List[str] = field(default_factory=list)
You can use one of two ways to attain further control over customization while working with Python dataclasses.
InitVar helps customize dataclasses in Python seamlessly. The function enables us to pass a specified field to __init__ and __post_init__ without storing the data in any class instance. Also, the method lets you key in parameters used exclusively during initialization.
from dataclasses import dataclass, field, InitVar from typing import List @dataclass class Book: '''Object for tracking physical books in a collection.''' name: str condition: InitVar[str] = "Good" weight: float = field(default=0.0, repr=False) shelf_id: int = field(init=False) chapters: List[str] = field(default_factory=list) def __post_init__(self, condition): if condition == "Unacceptable": self.shelf_id = None else: self.shelf_id = 0
Defining the field’s type as InitVar with the actual field type as a subtype signals @dataclass decorator not to classify it as a dataclass field and pass data as an argument on to __post_init__.
Like InitVar, the __post_init__ also lets you modify fields or other data types in a Python dataclass.
from dataclasses import dataclass, field, InitVar from typing import List @dataclass class Book: '''Object for tracking physical books in a collection.''' name: str weight: float = field(default=0.0, repr=False) shelf_id: Optional[int] = field(init=False) chapters: List[str] = field(default_factory=list) condition: str = field(default="Good", compare=False) def __post_init__(self): if self.condition == "Discarded": self.shelf_id = None else: self.shelf_id = 0
Python dataclasses provides us with a more efficient way to code new classes. Specifically, they act as an ideal replacement for functions like namedtuple, as they function the same way and create less hassle. In addition, a developer could also use them to replace nested dictionaries, for obviously, countering clumsiness.
Above are some applications for Python dataclasses. However, it is integral to understand sometimes classes can get the job done, and it is best not to make replacing each with a dataclass a knee-jerk reaction. First, evaluate the complexities involved, then decide whether to ditch the class for a dataclass or stick with it.
Also Read: A Guide To Assert In Python With Examples
Full Stack Java Developer | Writer | Recruiter, bridging the gap between exceptional talent and opportunities, for some of the biggest Fortune 500 companies.
Create a free profile and find your next great opportunity.
Sign up and find a perfect match for your team.
Xperti vets skilled professionals with its unique talent-matching process.
Connect and engage with technology enthusiasts.
© Xperti.io All Rights Reserved
Privacy
Terms of use