Python Dataclasses#

Note

Source: Python-specific — no direct equivalent in the C# edition. @dataclass (introduced in Python 3.7) automatically generates __init__, __repr__, and __eq__ for classes that primarily hold data, reducing boilerplate.

Writing a data-holding class by hand requires repeating each field name three or four times — in __init__ parameters, in self.x = x assignments, and in __repr__. The @dataclass decorator generates all of this automatically from a simple field declaration.

Basic Dataclass#

from dataclasses import dataclass

@dataclass
class Contact:
    name: str
    phone: str
    email: str

This single declaration is equivalent to:

class Contact:
    def __init__(self, name: str, phone: str, email: str):
        self.name = name
        self.phone = phone
        self.email = email

    def __repr__(self):
        return f"Contact(name={self.name!r}, phone={self.phone!r}, email={self.email!r})"

    def __eq__(self, other):
        return (self.name, self.phone, self.email) == (other.name, other.phone, other.email)
c = Contact("Marie Ortiz", "773-508-7890", "mortiz2@luc.edu")
print(c)
print(c == Contact("Marie Ortiz", "773-508-7890", "mortiz2@luc.edu"))

Output:

Contact(name='Marie Ortiz', phone='773-508-7890', email='mortiz2@luc.edu')
True

Default Values#

Fields can have default values, just like function parameters:

@dataclass
class Point:
    x: float = 0.0
    y: float = 0.0

origin = Point()
p = Point(3.0, 4.0)
print(origin, p)

Output:

Point(x=0.0, y=0.0) Point(x=3.0, y=4.0)

Adding Methods#

You can still add your own methods — @dataclass only generates the boilerplate:

import math

@dataclass
class Point:
    x: float
    y: float

    def distance_to(self, other):
        return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)

    def __str__(self):
        return f"({self.x}, {self.y})"

Immutable Dataclasses#

Pass frozen=True to make instances immutable (and hashable, so they can be used as dictionary keys):

@dataclass(frozen=True)
class Point:
    x: float
    y: float

p = Point(1.0, 2.0)
# p.x = 5.0   # raises FrozenInstanceError

When to Use @dataclass#

Use @dataclass when a class is primarily a container for related fields and you want automatic __init__ and __repr__. Write a class by hand when you need fine-grained control over initialisation, validation, or private attributes.