Dataclasses & NamedTuples

15 questions found

What does the @dataclass decorator automatically generate for a class?

Beginner
@dataclass automatically generates __init__ (accepting each declared field as a parameter), __repr__ (a readable string representation), and __eq__ (comparing all fields for equality) based on the class's type-annotated attributes, eliminating boilerplate you'd otherwise write by hand.
from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

p1 = Point(1, 2)
print(p1)              # Point(x=1, y=2) -- auto-generated __repr__
print(p1 == Point(1, 2))  # True -- auto-generated __eq__
Real-world example Quickly defining a simple data-holder class (like a Point or Config) without manually writing __init__ and __repr__.

Common follow-ups: Does @dataclass generate an __init__ that supports default values for fields, similar to a regular function?

Magic Methods & Operator Overloading

How do you create a simple immutable record using collections.namedtuple?

Beginner
namedtuple(typename, field_names) creates a NEW tuple subclass whose elements can be accessed both by INDEX (like a regular tuple) and by NAMED ATTRIBUTE, combining a tuple's lightweight immutability with readable, self-documenting field access.
from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
p = Point(1, 2)
print(p.x, p.y)   # 1 2 -- named attribute access
print(p[0], p[1]) # 1 2 -- also works like a regular tuple
Real-world example Representing a simple, lightweight, immutable record (like a coordinate or RGB color) without the overhead of a full class.

Common follow-ups: How does namedtuple compare to a regular tuple in terms of memory usage?

Data Types & Structures

How do you specify default values for dataclass fields, and what ordering restriction applies?

Intermediate
Assign a default value directly after the type annotation, exactly like a regular function parameter default — and just like function parameters, any field WITH a default must come AFTER all fields WITHOUT one, or Python raises a TypeError at class definition time.
@dataclass
class User:
    name: str          # required, no default
    role: str = "user"  # has a default, must come after required fields

u = User("Sam")
print(u.role)  # 'user'
Real-world example Defining sensible default values for optional configuration fields on a dataclass, like a default role or status.

Common follow-ups: What error occurs if you try to declare a field WITHOUT a default AFTER one that HAS a default?

Exception Handling

Why can't you use a mutable default value (like an empty list) directly as a dataclass field default, and how do you use field(default_factory=...) to fix it?

Intermediate
Using a mutable object (list, dict, set) as a default value would share the SAME object across every instance (the classic Python mutable-default-argument trap), so @dataclass explicitly raises a ValueError at class definition time if you try; field(default_factory=callable) instead calls the given zero-argument function to produce a FRESH object for each new instance.
from dataclasses import dataclass, field

@dataclass
class ShoppingCart:
    items: list = field(default_factory=list)  # a NEW list for each instance

cart1 = ShoppingCart()
cart1.items.append("apple")
cart2 = ShoppingCart()
print(cart2.items)  # [] -- independent from cart1's list, thanks to default_factory
Real-world example Avoiding the classic mutable-default-argument bug when a dataclass field should default to an empty list or dict.

Common follow-ups: What would happen if you simply wrote 'items: list = []' directly, without using field(default_factory=list)?

Functions & Scope

How do you make a dataclass immutable (read-only after creation) using frozen=True?

Intermediate
Pass frozen=True to the @dataclass decorator to make every field effectively read-only after __init__ runs — attempting to assign to any field afterward raises a FrozenInstanceError, and frozen dataclasses also automatically become hashable (if eq=True, the default), letting them be used as dict keys or set elements.
@dataclass(frozen=True)
class Point:
    x: int
    y: int

p = Point(1, 2)
# p.x = 99  # dataclasses.FrozenInstanceError: cannot assign to field 'x'

points_set = {Point(1, 2), Point(3, 4)}  # works: frozen dataclasses are hashable
Real-world example Creating an immutable value object (like a Point or Money amount) that's also safely usable as a dictionary key or set element.

Common follow-ups: Does frozen=True prevent mutation of a MUTABLE object stored INSIDE one of the dataclass's fields, like a list attribute?

Magic Methods & Operator Overloading

How does typing.NamedTuple differ from collections.namedtuple in terms of syntax and type annotation support?

Intermediate
typing.NamedTuple uses a class-based syntax with type ANNOTATIONS for each field (readable by type checkers like mypy), while collections.namedtuple uses a functional call with a string/list of field names and no built-in type information — both produce the same underlying immutable, tuple-based result at runtime.
from typing import NamedTuple

class Point(NamedTuple):
    x: int
    y: int

p = Point(1, 2)
print(p.x)  # 1, with full type-checker support for the 'x' field's type
Real-world example Choosing typing.NamedTuple over collections.namedtuple specifically to get static type checking support in a typed codebase.

Common follow-ups: Can typing.NamedTuple fields also have default values, similar to a dataclass?

Type Hints

How do you add validation logic to a dataclass field using __post_init__?

Advanced
__post_init__ is automatically called by the auto-generated __init__ RIGHT AFTER all fields are assigned, letting you add custom validation or derived-field computation without having to write __init__ manually from scratch.
@dataclass
class User:
    name: str
    age: int

    def __post_init__(self):
        if self.age < 0:
            raise ValueError("Age cannot be negative")

# User("Sam", -5)  # raises ValueError, caught by __post_init__
Real-world example Validating that a dataclass's fields satisfy business rules (like a non-negative age or a valid email format) right after construction.

Common follow-ups: How would you compute a DERIVED field (not passed to __init__ directly) inside __post_init__?

Exception Handling

How do you use dataclasses.field(compare=False) or field(repr=False) to exclude a specific field from the auto-generated __eq__ or __repr__?

Advanced
Pass compare=False to exclude a field from the auto-generated __eq__ (and ordering methods) comparison logic, or repr=False to exclude it from the auto-generated __repr__ output — useful for fields like an internal cache or a large binary blob that shouldn't affect equality or clutter the printed representation.
@dataclass
class User:
    name: str
    password_hash: str = field(repr=False)  # hidden from __repr__ for security
    last_login: str = field(compare=False, default="")  # doesn't affect equality checks

u = User("Sam", "hashed_value")
print(u)  # User(name='Sam', last_login='') -- password_hash omitted
Real-world example Excluding a sensitive field (like a password hash) from a dataclass's printed representation, or excluding a timestamp from equality comparisons.

Common follow-ups: How would you exclude a field from __init__ ENTIRELY as well, using field(init=False)?

Magic Methods & Operator Overloading

How do you implement custom ordering (<, <=, >, >=) for a dataclass using order=True, and what constraint does it place on field comparison?

Advanced
Passing order=True to @dataclass auto-generates __lt__, __le__, __gt__, and __ge__ that compare instances FIELD BY FIELD IN DECLARATION ORDER (like comparing tuples) — this requires ALL fields to support the relevant comparison operators themselves, or a TypeError occurs at comparison time.
@dataclass(order=True)
class Version:
    major: int
    minor: int
    patch: int

v1 = Version(1, 2, 0)
v2 = Version(1, 3, 0)
print(v1 < v2)  # True -- compares (major, minor, patch) tuples field by field
Real-world example Sorting a list of version numbers, dates, or priority-ranked records using their natural field order.

Common follow-ups: How would you make ONLY a subset of fields (not all of them) participate in the ordering comparison?

Magic Methods & Operator Overloading

How do you convert a dataclass instance to and from a dictionary using dataclasses.asdict() and manual reconstruction?

Advanced
dataclasses.asdict(instance) recursively converts a dataclass instance (including NESTED dataclasses) into a plain dictionary, useful for JSON serialization; there's no built-in 'fromdict', so reconstruction typically uses `ClassName(**data)` for simple flat cases, or a custom classmethod for nested structures.
from dataclasses import dataclass, asdict

@dataclass
class Address:
    city: str

@dataclass
class User:
    name: str
    address: Address

u = User("Sam", Address("NYC"))
print(asdict(u))  # {'name': 'Sam', 'address': {'city': 'NYC'}} -- fully recursive
Real-world example Serializing a dataclass instance (including nested dataclasses) into a plain dict, ready for json.dumps().

Common follow-ups: Why does asdict() perform a DEEP COPY of mutable field values by default, and how would you avoid that overhead?

Serialization (json pickle)

Showing 1–10 of 15