Dataclasses & NamedTuples
15 questions found
How would you implement inheritance between dataclasses, and what field-ordering rule must be respected across the hierarchy?
Advanced
A dataclass CAN inherit from another dataclass; the subclass's own fields are appended AFTER the parent's fields in the generated __init__ signature — meaning if the parent has any field WITH a default, every field the subclass adds must ALSO have a default, or you'll hit the same 'non-default argument follows default argument' error.
@dataclass
class Animal:
name: str
sound: str = "..."
@dataclass
class Dog(Animal):
breed: str = "unknown" # must have a default, since parent's 'sound' already has one
d = Dog(name="Rex", breed="Labrador")
print(d) # Dog(name='Rex', sound='...', breed='Labrador')
Real-world example
Building a hierarchy of related dataclasses (like a base Event class extended by specific event types) sharing common fields.
Common follow-ups: How does Python 3.10+'s kw_only=True parameter help avoid this field-ordering restriction entirely?
OOP
How do you implement a custom __eq__ or __hash__ on a dataclass while still benefiting from its other auto-generated methods?
Advanced
Pass eq=False (or hash appropriately) to @dataclass to SKIP auto-generating that specific method, then define your OWN __eq__ or __hash__ method in the class body — the decorator only generates methods you haven't disabled, letting you selectively override just the behavior you need custom logic for.
@dataclass(eq=False)
class CaseInsensitiveString:
value: str
def __eq__(self, other):
return isinstance(other, CaseInsensitiveString) and self.value.lower() == other.value.lower()
def __hash__(self):
return hash(self.value.lower())
Real-world example
Implementing case-insensitive equality for a dataclass wrapping a string, where the default field-by-field comparison wouldn't be correct.
Common follow-ups: Why does defining a custom __eq__ on a regular (non-dataclass) class automatically set __hash__ to None unless you also define __hash__?
Magic Methods & Operator Overloading
How would you use dataclasses.replace() to create a modified copy of an immutable (frozen) dataclass instance?
Advanced
dataclasses.replace(instance, **changes) creates a NEW instance of the same dataclass, copying all existing field values EXCEPT the ones you explicitly override via keyword arguments — essential for 'modifying' a frozen dataclass, since you can't mutate it directly.
from dataclasses import dataclass, replace
@dataclass(frozen=True)
class Point:
x: int
y: int
p1 = Point(1, 2)
p2 = replace(p1, y=99) # creates a NEW Point, since p1 is frozen and can't be mutated
print(p1, p2) # Point(x=1, y=2) Point(x=1, y=99)
Real-world example
Producing a modified copy of an immutable configuration or value object without mutating the original.
Common follow-ups: How does dataclasses.replace() handle fields that were marked with init=False?
Magic Methods & Operator Overloading
When would you choose a NamedTuple over a @dataclass, and vice versa, given their overlapping use cases?
Advanced
Choose NamedTuple when you want tuple-like behavior (positional unpacking, iteration, indexing, natural immutability, and lower memory overhead) for simple, lightweight records; choose @dataclass when you need MUTABILITY (unless frozen), custom methods/validation via __post_init__, inheritance, or don't need tuple-style unpacking/indexing semantics.
from typing import NamedTuple
from dataclasses import dataclass
class PointTuple(NamedTuple): # lightweight, tuple-like, unpacking works
x: int; y: int
x, y = PointTuple(1, 2) # tuple unpacking works naturally
@dataclass
class PointClass: # mutable, supports validation, no tuple unpacking
x: int; y: int
Real-world example
Choosing NamedTuple for a simple return value that benefits from tuple unpacking, versus a dataclass for a mutable domain entity with validation.
Common follow-ups: Can a dataclass be made to support tuple-style unpacking too, by implementing __iter__?
Magic Methods & Operator Overloading
How would you use Python 3.10+'s kw_only=True (or per-field kw_only) to require dataclass fields be passed as keyword arguments only?
Advanced
Setting kw_only=True on @dataclass (or on an individual field()) forces those fields to be passed by KEYWORD ONLY in __init__, completely sidestepping the 'non-default argument follows default argument' ordering restriction, since keyword-only arguments don't have the same strict positional ordering requirement.
@dataclass(kw_only=True)
class Config:
debug: bool = False
name: str # no default, but still valid since ALL fields are keyword-only now
c = Config(name="MyApp") # must use keyword args: Config(name="MyApp", debug=True)
# Config("MyApp") # TypeError: takes 1 positional argument but 2 were given
Real-world example
Designing a configuration dataclass with many optional fields where enforcing keyword-only construction improves call-site readability.
Common follow-ups: Can you mix kw_only fields with regular positional fields in the SAME dataclass, and if so, how are they ordered?
Functions & Scope