When you need lightweight, immutable data structures that are more readable than plain tuples, NamedTuples provide named field access while retaining tuple efficiency. They are memory-efficient, hashable, and work seamlessly with tuple unpacking.

Why Use NamedTuples?

Tuple Unpacking and _fields

NamedTuples support unpacking and provide metadata access through _fields and _asdict().

basic.py
# Basic namedtuple usage

from collections import namedtuple

# Create a namedtuple type
Point = namedtuple('Point', ['x', 'y'])

# Create instances
p1 = 
p2 = Point(x=30, y=40)

# Access by name
print(f"p1: x={p1.x}, y={p1.y}")

# Access by index (still a tuple)
print(f"p1[0]={p1[0]}, p1[1]={p1[1]}")

# Tuple operations
print(f"Length: {len(p1)}")
print(f"As tuple: {tuple(p1)}")
# Basic namedtuple usage

from collections import namedtuple

# Create a namedtuple type
Point = namedtuple('Point', ['x', 'y'])

# Create instances
p1 = 
p2 = Point(x=30, y=40)

# Access by name
print(f"p1: x={p1.x}, y={p1.y}")

# Access by index (still a tuple)
print(f"p1[0]={p1[0]}, p1[1]={p1[1]}")

# Tuple operations
print(f"Length: {len(p1)}")
print(f"As tuple: {tuple(p1)}")
# Basic namedtuple usage

from collections import namedtuple

# Create a namedtuple type
Point = namedtuple('Point', ['x', 'y'])

# Create instances
p1 = 
p2 = Point(x=30, y=40)

# Access by name
print(f"p1: x={p1.x}, y={p1.y}")

# Access by index (still a tuple)
print(f"p1[0]={p1[0]}, p1[1]={p1[1]}")

# Tuple operations
print(f"Length: {len(p1)}")
print(f"As tuple: {tuple(p1)}")
typed_with_methods.py
# Typed NamedTuple with methods

from typing import NamedTuple

class Point(NamedTuple):
    x: float
    y: float
    
    def distance_from_origin(self) -> float:
        return (self.x ** 2 + self.y ** 2) ** 0.5
    
    def distance_to(self, other: 'Point') -> float:
        dx = self.x - other.x
        dy = self.y - other.y
        return (dx ** 2 + dy ** 2) ** 0.5

# Create points
p1 = Point(3.0, 4.0)
p2 = Point(6.0, 8.0)

print(f"p1 distance from origin: {p1.distance_from_origin():.2f}")
print(f"Distance from p1 to p2: {p1.distance_to(p2):.2f}")
default_values.py
# NamedTuple with default values

from typing import NamedTuple

class Person(NamedTuple):
    name: str
    age: int
    country: str = "USA"
    active: bool = True

# Use defaults
person1 = Person("Alice", 30)
print(person1)

# Override defaults
person2 = Person("Bob", 25, "Canada", False)
print(person2)

# Partial override
person3 = Person("Charlie", 35, country="UK")
print(person3)
immutable_replace.py
# Immutability and _replace()

from typing import NamedTuple

class Config(NamedTuple):
    host: str
    port: int
    debug: bool

# Create config
config = Config("localhost", 8080, False)
print(f"Original: {config}")

# Cannot modify (immutable)
try:
    config.port = 9000
except AttributeError as e:
    print(f"Error: {e}")

# Use _replace() to create modified copy
new_config = config._replace(debug=True)
print(f"Modified: {new_config}")
print(f"Original unchanged: {config}")

# Multiple changes
prod_config = config._replace(host="0.0.0.0", port=80)
print(f"Production: {prod_config}")
unpacking_fields.py
# Tuple unpacking and _fields

from typing import NamedTuple

class Employee(NamedTuple):
    name: str
    id: int
    department: str
    salary: float

employee = Employee("Alice Johnson", 1001, "Engineering", 95000)

# Tuple unpacking
name, emp_id, dept, salary = employee
print(f"{name} (ID: {emp_id}) works in {dept}")

# Access _fields attribute
print(f"\nFields: {employee._fields}")

# Convert to dict using _asdict()
emp_dict = employee._asdict()
print(f"\nAs dict: {emp_dict}")

# Create from dict
data = {"name": "Bob Smith", "id": 1002, "department": "Sales", "salary": 85000}
new_employee = Employee(**data)
print(f"\nFrom dict: {new_employee}")

@seealso dataclass_intro "Dataclasses for mutable data" @seealso typing_intro "Type hints"

namedtuple A lightweight, immutable data structure that combines tuple efficiency with named field access, created using collections.namedtuple or typing.NamedTuple.
_replace() A method that creates a new NamedTuple instance with specified fields replaced, since NamedTuples are immutable and cannot be modified in place.

Exercise: practical.py

Create a Color NamedTuple with RGB values, hex conversion, and brightness calculation methods