Difficulty: Intermediate
What are the differences between namedtuple, typing.NamedTuple, and dataclass?
All three create structured record types, but differ in features:
namedtuple (collections): immutable tuple subclass, memory-efficient, fast, no type hints typing.NamedTuple: like namedtuple but with type annotations and method definitions dataclass: mutable by default, supports default values, methods, inheritance, not a tuple
When to use: - namedtuple/NamedTuple: read-only records, unpacking, tuple compatibility needed - dataclass: mutable records with behavior, validation, complex defaults - dataclass(frozen=True): immutable dataclass (not tuple, but hashable)
from collections import namedtuple
from typing import NamedTuple
from dataclasses import dataclass
# 1. collections.namedtuple
Point1 = namedtuple('Point1', ['x', 'y'])
# 2. typing.NamedTuple - with types and methods
class Point2(NamedTuple):
x: float
y: float
label: str = 'point'
def distance_from_origin(self):
return (self.x2 + self.y2) 0.5
# 3. dataclass
@dataclass
class Point3:
x: float
y: float
label: str = 'point'
def distance_from_origin(self):
return (self.x2 + self.y2) 0.5
p1 = Point1(3.0, 4.0)
p2 = Point2(3.0, 4.0)
p3 = Point3(3.0, 4.0)
# Tuple behavior (namedtuple and NamedTuple)
print(isinstance(p1, tuple)) # True
print(isinstance(p2, tuple)) # True
print(isinstance(p3, tuple)) # False
x, y = p2 # Unpacking works
print(x, y)
# Immutability
try:
p2.x = 99 # AttributeError
except AttributeError:
print('NamedTuple is immutable')
p3.x = 99 # dataclass is mutable by default
print(p3.x)
namedtuple and NamedTuple are tuples - they support unpacking and are immutable. dataclass is a regular class - mutable and not a tuple.
import sys
from collections import namedtuple
from typing import NamedTuple
from dataclasses import dataclass
Point = namedtuple('Point', ['x', 'y', 'z'])
class TypedPoint(NamedTuple):
x: float; y: float; z: float
@dataclass
class DPoint:
x: float; y: float; z: float
@dataclass(slots=True)
class SPoint:
x: float; y: float; z: float
p1 = Point(1, 2, 3)
p2 = TypedPoint(1, 2, 3)
p3 = DPoint(1, 2, 3)
p4 = SPoint(1, 2, 3)
print('namedtuple:', sys.getsizeof(p1)) # 72
print('NamedTuple:', sys.getsizeof(p2)) # 72
print('dataclass:', sys.getsizeof(p3)) # 48 + dict overhead
print('dataclass slots:', sys.getsizeof(p4)) # 56
# Conversion
print(dict(p1._asdict())) # {'x': 1, 'y': 2, 'z': 3}
print(p1._replace(z=99)) # Point(x=1, y=2, z=99) - new instance
_asdict() converts to OrderedDict. _replace() creates a modified copy (like copy() for frozen dataclasses).
namedtuple, NamedTuple, dataclass, tuple, Record Types