Python Named Tuples

In the last lesson you learned Type Hints, where you label what kind of value a thing holds. Now let’s fix a small annoyance that shows up the moment you start passing data around as tuples.

A tuple holds a few values together. That part is fine. The pain is reading them later. You see point[0] and point[1] in your code. Then you have to stop and think. Wait, which one was the x and which one was the y? A named tuple solves this. It gives each position a name, so you write point.x and point.y instead.

πŸ€” Why Named Tuples

Say you store a location as a plain tuple.

point = (4, 9)
print(point[0]) # what is this again?
print(point[1])

Output

4
9

The numbers come out fine. But point[0] tells you nothing about what it means. A week later you are guessing. And if someone swaps the order, every reader has to learn it again.

The fix is one line. A named tuple lets you name each field. Now the code reads like plain English. You stop counting positions.

🧩 What a Named Tuple Is

A named tuple is a tuple whose fields have names. Think of it like a row in a contacts app. The row still has a fixed set of columns. But instead of saying β€œgive me column 0”, you say β€œgive me the name”. Same row, clearer access.

It is built on top of a regular tuple. So it keeps everything a tuple gives you. It is still ordered. It is still immutable, which means once you create it you cannot change its values. And you can still loop over it or unpack it like any tuple.

You make one with namedtuple from the collections module. That module ships with Python. No install needed.

from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(4, 9)
print(p.x)
print(p.y)
print(p)

Output

4
9
Point(x=4, y=9)

Here is what each line is doing:

  • namedtuple("Point", ["x", "y"]) builds a new type called Point with two fields, x and y. You assign it to a variable, usually with the same name.
  • Point(4, 9) creates one. The 4 goes into x, and the 9 goes into y.
  • p.x and p.y read the fields by name. Much clearer than p[0].
  • Printing p shows the field names too, so debugging is easier.

Tip

You can also pass the field names as one space-separated string: namedtuple("Point", "x y"). Both ways do the same thing.

πŸ” It Is Still a Tuple

The β€œnamed” part is a bonus on top. Underneath it is a plain tuple. So all the old tuple tricks still work.

from collections import namedtuple
Point = namedtuple("Point", "x y")
p = Point(4, 9)
print(p[0]) # index still works
x, y = p # unpacking still works
print(x, y)
print(len(p)) # length works too

Output

4
4 9
2

So you do not lose anything. You read by name when you want it clear. And you still index or unpack when that is handier.

Because it is a tuple, it is immutable. Trying to change a field is an error.

from collections import namedtuple
Point = namedtuple("Point", "x y")
p = Point(4, 9)
p.x = 10 # ❌ this raises an error

Output

Traceback (most recent call last):
File "main.py", line 6, in <module>
p.x = 10
AttributeError: can't set attribute

That is on purpose. A named tuple is for a small record you read but do not edit. Do you need a fresh copy with one value changed? Use _replace. It gives you a new named tuple and leaves the original alone.

from collections import namedtuple
Point = namedtuple("Point", "x y")
p = Point(4, 9)
moved = p._replace(x=10)
print(p)
print(moved)

Output

Point(x=4, y=9)
Point(x=10, y=9)

🌍 A More Real Example

Imagine you are reading rows from a contacts list. Each person has a name, an email, and a city. A named tuple makes each row easy to read.

from collections import namedtuple
Contact = namedtuple("Contact", "name email city")
people = [
Contact("Alex", "alex@example.com", "Berlin"),
Contact("Riya", "riya@example.com", "Toronto"),
Contact("Arjun", "arjun@example.com", "Lagos"),
]
for person in people:
print(f"{person.name} from {person.city}")

Output

Alex from Berlin
Riya from Toronto
Arjun from Lagos

See how person.name and person.city read like a sentence? If these were plain tuples you would write person[0] and person[2]. Then you would be counting columns every time. The names carry the meaning for you.

πŸ†• The typing.NamedTuple Version

There is a second way to make one. It uses NamedTuple from the typing module. You write it like a small class, and you get to add type hints for each field. Many people find this version easier to read.

from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
p = Point(4, 9)
print(p.x)
print(p)

Output

4
Point(x=4, y=9)

This makes the exact same kind of object as the collections version. The difference is style. The class form shows the field names and their types right there. It also works well with the type hints you saw in the last lesson. Pick whichever reads better to you.

πŸ“Š Named Tuple vs Dataclass

You may have heard of a dataclass, which is another way to hold a small bundle of fields. Both group named fields together. So when do you reach for which? Here is the short version.

Question Named tuple Dataclass
Can you change a field after creating it? No, it is immutable Yes by default (can be made immutable)
Does it act like a tuple (index, unpack)? Yes No
Good for methods and logic? Not really, keep it simple Yes, add methods freely
Best fit A small, fixed, read-only record A richer object you will change or grow

So the rule of thumb is simple. Do you just need a tiny, fixed record that you read and pass around and never edit? Then a named tuple is perfect. Will the thing change over time, or do you want to attach behavior to it? Then a dataclass fits better.

⚠️ Common Mistakes

A few things trip people up the first time.

  • Trying to edit a field. Named tuples are read-only. Use _replace to get a changed copy instead.
# ❌ Avoid: changing in place
p.x = 10
# βœ… Good: make a new one with the change
moved = p._replace(x=10)
  • Passing the values in the wrong order. The first value fills the first field, and so on. Naming the arguments keeps it safe.
# ❌ Avoid: easy to mix up the order
Contact("alex@example.com", "Alex", "Berlin")
# βœ… Good: name the fields so the order cannot cause a mistake
Contact(name="Alex", email="alex@example.com", city="Berlin")
  • Reaching for a named tuple when you really need a full class. Does your record need methods, validation, or fields you will update? Then use a class or a dataclass instead.

βœ… Best Practices

Keep these habits and named tuples stay pleasant to use.

  • Name the type with a capital letter, like Point or Contact, since it acts like a small type.
  • Use it only for small, fixed records that you read but do not change.
  • Reach for the typing.NamedTuple class form when you want type hints on the fields.
  • When you need a changed version, use _replace and keep the original untouched.
  • Do you find yourself wanting to add methods or edit fields a lot? Then switch to a dataclass.

🧩 What You’ve Learned

βœ… A named tuple is a tuple whose fields have names, so you read point.x instead of point[0].

βœ… You create one with namedtuple from collections, or with the class-style NamedTuple from typing.

βœ… It is still a real tuple, so it is ordered, you can index and unpack it, and it is immutable.

βœ… To get a changed version you use _replace, which returns a new named tuple.

βœ… Use it for a small, fixed, read-only record. Reach for a dataclass when the thing will change or needs methods.

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    What is the main benefit of a named tuple over a plain tuple?

    Why: Named tuples give each position a name, so point.x is far clearer than point[0].

  2. 2

    What happens if you try to do p.x = 10 on a named tuple?

    Why: A named tuple is still a tuple, so it is immutable and cannot be changed in place.

  3. 3

    How do you get a named tuple with one field changed?

    Why: _replace returns a new named tuple with the change and leaves the original untouched.

  4. 4

    When should you pick a dataclass instead of a named tuple?

    Why: Named tuples fit small fixed records; a dataclass fits objects that change or carry behavior.

πŸš€ What’s Next?

You now have a clean way to pass small records around. Next we step outside your own program and start talking to other services on the internet.

What is an API?

Share & Connect