Logo
Python Introduction
Python Installation and Project Setup
Running Python Programs
Python Syntax and Indentation Rules
Python Variables
Python Comments
Python Data Types
Python Type Conversion and Type Checking
Python Input and Output Functions
Python Operators
Python Arithmetic Operators
Python Assignment Operators
Python Logical Operators
Python Comparison Operators
Python Bitwise Operators
Python Membership Operators
Python Identity Operators
Python Walrus Operator
Python Operator Precedence
Python Conditional Statements
Python if Statement
Python if else
Python if elif else
Python match case Statement
Python Loops
Python for Loop
Python for else Loop
Python while Loop
Python break statement
Python continue statement
Python pass statement
Python Strings
Python String Slicing
Python String Concatenation
Python String Formatting
Python Escape Characters
Python Lists
Python Access List Items
Python Add List Items
Python Change List Items
Python Remove List Items
Python Sort Lists
Python Copy Lists
Python Join Lists
Python List Methods
Python Tuples
Python Access Tuple Items
Python Update Tuples
Python Unpack Tuples
Python Loop Tuples
Python Join Tuples
Python Tuple Methods
Python NamedTuple
Python Sets
Python Access Set Items
Python Add Set Items
Python Remove Set Items
Python Join Sets
Python Copy Sets
Python Dictionaries
Python Functions
Python Lambda Functions
Python Higher Order Functions
Python Classes and Objects
Python OOP Principles
Python Magic Methods
Python Context Managers
Python Error Handling and Debugging
Python File Handling
Python Modules and Packages
Python Iterators and Generators

Python NamedTuple

Python NamedTuple gives you a way to create lightweight, immutable objects that behave like tuples but let you access elements by name instead of index. If you have ever worked with regular tuples and found yourself forgetting which index holds which value, Python NamedTuple solves that problem elegantly. It combines the efficiency of tuples with the readability of classes, making your code cleaner and easier to maintain.

Python NamedTuple lives in the collections module as part of the standard library. You can also define namedtuples using the typing module for a more modern, class-based syntax. Both approaches create tuple subclasses where each position has a meaningful name.

Creating a NamedTuple with collections.namedtuple

The most common way to create a Python NamedTuple is using the namedtuple factory function from the collections module. You pass it a type name and a sequence of field names, and it returns a new class that you can use to create instances.

python
from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 7)
print(p)
print(p.x)
print(p.y)
Output
Point(x=3, y=7)
3
7

The namedtuple function created a new class called Point with two fields, x and y. You can access each value by its field name using dot notation, which is much more readable than using numeric indices like a regular tuple.

You can also specify field names as a single space-separated or comma-separated string instead of a list.

python
from collections import namedtuple

Color = namedtuple('Color', 'red green blue')
c = Color(255, 128, 0)
print(c)
print(c.red)
print(c.green)
print(c.blue)
Output
Color(red=255, green=128, blue=0)
255
128
0

Both formats work exactly the same way. The string format is a convenient shorthand when you have simple field names.

Creating a NamedTuple with typing.NamedTuple

Python 3.6 introduced a class-based syntax for defining namedtuples using the typing module. This approach lets you add type annotations and feels more like writing a regular class.

python
from typing import NamedTuple

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

emp = Employee('Alice', 'Engineering', 95000.0)
print(emp)
print(emp.name)
print(emp.department)
print(emp.salary)
Output
Employee(name='Alice', department='Engineering', salary=95000.0)
Alice
Engineering
95000.0

The typing.NamedTuple approach is preferred in modern Python code because it provides type hints and reads like a class definition. The resulting namedtuple works identically to one created with collections.namedtuple.

Accessing Fields by Name and Index

Since a Python NamedTuple is a subclass of tuple, you can access elements both by name and by index. This dual access makes namedtuples versatile and backwards compatible with code that expects regular tuples.

python
from collections import namedtuple

Book = namedtuple('Book', ['title', 'author', 'year'])
book = Book('The Pragmatic Programmer', 'David Thomas', 1999)

print(book.title)
print(book[0])
print(book.author)
print(book[1])
print(book.year)
print(book[2])
Output
The Pragmatic Programmer
The Pragmatic Programmer
David Thomas
David Thomas
1999
1999

Both book.title and book[0] return the same value. Named access is clearer in most situations, but index access is useful when you need to iterate or unpack values.

Unpacking and Iteration

Python NamedTuple instances support unpacking just like regular tuples. You can assign each field to a separate variable in a single statement, which is handy when passing namedtuple data to functions or using it in loops.

python
from collections import namedtuple

Coordinates = namedtuple('Coordinates', ['latitude', 'longitude'])
location = Coordinates(40.7128, -74.0060)

lat, lon = location
print(f'Latitude: {lat}')
print(f'Longitude: {lon}')

print('Iterating over fields:')
for value in location:
    print(value)
Output
Latitude: 40.7128
Longitude: -74.006
Iterating over fields:
40.7128
-74.006

Unpacking works because a namedtuple is still a tuple underneath. You get all the tuple behaviors like iteration, slicing, and length checking for free.

Immutability of NamedTuple

A Python NamedTuple is immutable, meaning you cannot change its field values after creation. This is a key property that makes namedtuples safe to use as dictionary keys, set members, and in situations where you need data that should not change.

python
from collections import namedtuple

Settings = namedtuple('Settings', ['theme', 'font_size'])
config = Settings('dark', 14)

print(config)

try:
    config.theme = 'light'
except AttributeError as e:
    print(f'Error: {e}')
Output
Settings(theme='dark', font_size=14)
Error: can't set attribute

Attempting to modify a field raises an AttributeError. If you need a modified copy, use the _replace method instead of trying to change the original.

The _replace Method

The _replace method creates a new namedtuple instance with some fields changed while keeping the rest unchanged. Since namedtuples are immutable, this is the standard way to create modified versions of your Python NamedTuple objects.

python
from collections import namedtuple

Product = namedtuple('Product', ['name', 'price', 'stock'])
item = Product('Keyboard', 49.99, 150)
print(f'Original: {item}')

updated_item = item._replace(price=39.99, stock=200)
print(f'Updated: {updated_item}')
print(f'Original unchanged: {item}')
Output
Original: Product(name='Keyboard', price=49.99, stock=150)
Updated: Product(name='Keyboard', price=39.99, stock=200)
Original unchanged: Product(name='Keyboard', price=49.99, stock=150)

The _replace method returns a brand new namedtuple. The original stays exactly as it was, which is the expected behavior for immutable objects.

The _fields and _asdict Methods

Python NamedTuple provides several useful built-in methods. The _fields attribute returns a tuple of field names, and _asdict converts the namedtuple into an OrderedDict (or a regular dict in Python 3.8+).

python
from collections import namedtuple

Student = namedtuple('Student', ['name', 'grade', 'gpa'])
student = Student('Bob', 'A', 3.9)

print(f'Fields: {student._fields}')
print(f'As dict: {student._asdict()}')

student_dict = student._asdict()
print(f'Name from dict: {student_dict["name"]}')
Output
Fields: ('name', 'grade', 'gpa')
As dict: {'name': 'Bob', 'grade': 'A', 'gpa': 3.9}
Name from dict: Bob

The _fields attribute is helpful when you need to inspect the structure of a namedtuple dynamically. The _asdict method is perfect for serializing namedtuples to JSON or passing data to functions that expect dictionaries.

Default Values in NamedTuple

You can set default values for Python NamedTuple fields. With the typing.NamedTuple syntax, defaults work exactly like they do in class definitions. With collections.namedtuple, you use the defaults parameter.

python
from collections import namedtuple

Connection = namedtuple('Connection', ['host', 'port', 'timeout'], defaults=[3306, 30])
conn1 = Connection('localhost')
conn2 = Connection('db.example.com', 5432)
conn3 = Connection('db.example.com', 5432, 60)

print(conn1)
print(conn2)
print(conn3)
Output
Connection(host='localhost', port=3306, timeout=30)
Connection(host='db.example.com', port=5432, timeout=30)
Connection(host='db.example.com', port=5432, timeout=60)

Defaults are applied from right to left. In this example, port defaults to 3306 and timeout defaults to 30, but host has no default and must always be provided.

Here is the same thing using the typing.NamedTuple syntax.

python
from typing import NamedTuple

class Connection(NamedTuple):
    host: str
    port: int = 3306
    timeout: int = 30

conn = Connection('localhost')
print(conn)
Output
Connection(host='localhost', port=3306, timeout=30)

The typing syntax makes defaults more explicit since each field shows its type and default value on the same line.

Creating NamedTuple from Iterable with _make

The _make class method creates a Python NamedTuple instance from an existing iterable like a list or a tuple. This is useful when you are reading data from files, databases, or APIs and need to convert raw sequences into structured namedtuples.

python
from collections import namedtuple

Record = namedtuple('Record', ['id', 'name', 'score'])

data_list = [101, 'Charlie', 88.5]
record = Record._make(data_list)
print(record)

csv_row = '102,Diana,92.3'
values = csv_row.split(',')
record2 = Record._make([int(values[0]), values[1], float(values[2])])
print(record2)
Output
Record(id=101, name='Charlie', score=88.5)
Record(id=102, name='Diana', score=92.3)

The _make method is a clean alternative to unpacking arguments manually. It validates that the iterable has the right number of elements and raises a TypeError if it does not match.

NamedTuple vs Regular Tuple

A Python NamedTuple is more readable and self-documenting compared to a regular tuple. Here is a side-by-side comparison to see the difference.

python
from collections import namedtuple

regular_tuple = ('Alice', 30, 'Engineer')
print(f'Name: {regular_tuple[0]}')
print(f'Age: {regular_tuple[1]}')
print(f'Role: {regular_tuple[2]}')

Person = namedtuple('Person', ['name', 'age', 'role'])
named = Person('Alice', 30, 'Engineer')
print(f'Name: {named.name}')
print(f'Age: {named.age}')
print(f'Role: {named.role}')

print(f'Are they equal? {regular_tuple == named}')
print(f'Type of named: {type(named).__bases__}')
Output
Name: Alice
Age: 30
Role: Engineer
Name: Alice
Age: 30
Role: Engineer
Are they equal? True
Type of named: (<class 'tuple'>,)

The namedtuple version is self-explanatory. You know exactly what each field represents without needing comments. And since namedtuple inherits from tuple, it is fully compatible wherever regular tuples are expected.

Complete Working Example

This example brings together everything covered about Python NamedTuple. It defines a namedtuple for managing a simple inventory system, demonstrates creation, access, modification with _replace, conversion with _asdict, and building from raw data with _make.

python
from typing import NamedTuple


class InventoryItem(NamedTuple):
    sku: str
    name: str
    quantity: int
    price: float
    category: str = 'General'


def display_item(item):
    print(f'  SKU: {item.sku}')
    print(f'  Name: {item.name}')
    print(f'  Quantity: {item.quantity}')
    print(f'  Price: ${item.price:.2f}')
    print(f'  Category: {item.category}')
    print()


item1 = InventoryItem('WDG-001', 'Wireless Mouse', 45, 29.99, 'Electronics')
item2 = InventoryItem('WDG-002', 'USB Cable', 200, 7.49)

print('--- Inventory Items ---')
print('Item 1:')
display_item(item1)
print('Item 2 (default category):')
display_item(item2)

print(f'Fields: {InventoryItem._fields}')
print()

updated_item1 = item1._replace(quantity=40, price=24.99)
print('After restocking and price change:')
display_item(updated_item1)

item_dict = item1._asdict()
print(f'Item 1 as dictionary: {item_dict}')
print()

raw_data = ['WDG-003', 'Laptop Stand', 30, 54.99, 'Furniture']
item3 = InventoryItem._make(raw_data)
print('Item created from raw data:')
display_item(item3)

inventory = [item1, item2, item3]
total_value = sum(item.quantity * item.price for item in inventory)
print(f'Total inventory value: ${total_value:.2f}')

print('Items with quantity under 50:')
for item in inventory:
    if item.quantity < 50:
        print(f'  {item.name} - {item.quantity} units')
Output
--- Inventory Items ---
Item 1:
  SKU: WDG-001
  Name: Wireless Mouse
  Quantity: 45
  Price: $29.99
  Category: Electronics

Item 2 (default category):
  SKU: WDG-002
  Name: USB Cable
  Quantity: 200
  Price: $7.49
  Category: General

Fields: ('sku', 'name', 'quantity', 'price', 'category')

After restocking and price change:
  SKU: WDG-001
  Name: Wireless Mouse
  Quantity: 40
  Price: $24.99
  Category: Electronics

Item 1 as dictionary: {'sku': 'WDG-001', 'name': 'Wireless Mouse', 'quantity': 45, 'price': 29.99, 'category': 'Electronics'}

Item created from raw data:
  SKU: WDG-003
  Name: Laptop Stand
  Quantity: 30
  Price: $54.99
  Category: Furniture

Total inventory value: $4497.25

Items with quantity under 50:
  Wireless Mouse - 45 units
  Laptop Stand - 30 units