Python Tuples: Immutable Sequences

A tuple is a list that cannot change. That single restriction makes it usable as a dictionary key, safe to share, and the natural way to return several values at once.

Creating a tuple

empty = ()
empty_too = tuple()

point = (3, 7)
person = ("Meera", 27, "Pune")
mixed = (1, "two", [3, 4])

no_brackets = 3, 7            # the brackets are optional
print(type(no_brackets))      # <class 'tuple'>

from_list = tuple([1, 2, 3])
from_string = tuple("abc")    # ('a', 'b', 'c')
It is the comma that makes a tuple, not the brackets. The brackets are for grouping and readability. That is why the single element case is unusual.

The one element tuple

not_a_tuple = (5)
print(type(not_a_tuple))      # <class 'int'> - just a number in brackets

single = (5,)                 # the trailing comma is what matters
print(type(single), len(single))   # <class 'tuple'> 1

also_single = 5,
print(type(also_single))      # <class 'tuple'>

Tuples are immutable

point = (3, 7)

# point[0] = 5            # TypeError: object does not support item assignment
# point.append(9)         # AttributeError: no such method
# del point[0]            # TypeError

point = (5, 7)            # allowed: this rebinds the NAME to a new tuple

Only two methods exist, and neither changes anything:

values = (1, 2, 2, 3)

print(values.count(2))        # 2
print(values.index(3))        # 3
print(len(values))            # 4
print(2 in values)            # True

Immutable does not mean the contents are frozen

record = ("Meera", [92, 78])

# record[1] = [50]        # TypeError - cannot replace the element
record[1].append(85)      # but the LIST inside can still be changed
print(record)             # ('Meera', [92, 78, 85])

The tuple guarantees that its references never change. It says nothing about the objects those references point at. A tuple containing a list is therefore not hashable:

print(hash(("a", 1)))          # fine
# print(hash(("a", [1])))      # TypeError: unhashable type: 'list'

Everything a list can do, except change

values = (10, 20, 30, 40, 50)

print(values[0], values[-1])      # 10 50
print(values[1:4])                # (20, 30, 40) - slicing returns a tuple
print(values + (60,))             # concatenation builds a NEW tuple
print(values * 2)                 # repetition
print(len(values), sum(values), max(values))
print(sorted(values, reverse=True))    # returns a LIST, not a tuple

for value in values:
    print(value, end=" ")
print()

Tuple or list?

TupleList
ChangeableNoYes
As a dictionary keyYesNo
In a setYesNo
MemorySlightly lessSlightly more
Creation speedSlightly fasterSlightly slower
Typical meaningOne record with fixed fieldsMany items of the same kind

The performance difference is real but small; it is almost never the reason to choose. The meaningful question is what the collection represents:

point = (12.5, 48.2)                      # a record: x and y, always exactly two
colours = ["red", "green", "blue"]        # a collection: could gain a fourth

date = (2026, 8, 22)                      # fields that belong together
temperatures = [21.5, 22.0, 19.8]         # a series of the same measurement

A useful test: if you would be comfortable sorting it, it is probably a list. Sorting a point would be meaningless.

Tuples as dictionary keys

board = {}
board[(0, 0)] = "X"
board[(1, 2)] = "O"

print(board[(0, 0)])          # X
print(board)                  # {(0, 0): 'X', (1, 2): 'O'}

distances = {
    ("Pune", "Mumbai"): 150,
    ("Pune", "Nashik"): 210,
}
print(distances[("Pune", "Mumbai")])      # 150

This is the clearest reason tuples exist. A coordinate, a pair of cities or a composite identifier can be a key directly, with no string concatenation.

Returning several values

def statistics(values):
    return min(values), max(values), sum(values) / len(values)


low, high, average = statistics([4, 8, 15, 16])
print(low, high, average)          # 4 16 10.75

result = statistics([1, 2, 3])
print(type(result))                # <class 'tuple'>
print(result[1])                   # 3

A function that appears to return several values is returning one tuple. Python then unpacks it at the call site. divmod, str.partition and dict.popitem all work this way.

Named tuples

Positional access becomes unreadable once a tuple has more than three fields. namedtuple keeps the tuple behaviour and adds names.

from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
p = Point(3, 7)

print(p.x, p.y)          # 3 7
print(p[0], p[1])        # 3 7 - still a tuple
print(p)                 # Point(x=3, y=7)

x, y = p                 # still unpacks
print(x + y)             # 10

moved = p._replace(x=10) # returns a NEW point; still immutable
print(moved)             # Point(x=10, y=7)
Employee = namedtuple("Employee", "name role salary")
staff = [
    Employee("Meera", "engineer", 90000),
    Employee("Arun", "designer", 75000),
]

for member in staff:
    print(f"{member.name} ({member.role})")

print(max(staff, key=lambda e: e.salary).name)     # Meera

Common mistakes

  • Writing (5) and expecting a tuple. Only (5,) is one.
  • Believing a tuple protects mutable objects inside it.
  • Trying to sort a tuple in place. sorted() returns a list.
  • Leaving a stray trailing comma after a value, silently creating a tuple: x = 5,.
  • Using a list where the value is a fixed record, losing the ability to use it as a key.
  • Assuming tuple concatenation is cheap in a loop. Each + builds a whole new tuple.

Best practices

  • Use a tuple for a fixed size record, a list for a variable collection of like things.
  • Use namedtuple once a tuple has three or more fields.
  • Return a tuple from a function that produces several related values.
  • Use tuples as dictionary keys instead of joining values into a string.
  • Be deliberate about trailing commas; in Python they are never decorative.

Practice

  1. Explain why len((5)) raises but len((5,)) is 1.
  2. Build a dictionary that stores a value for every cell of a 3 by 3 board using tuple keys.
  3. Write a function returning the minimum, maximum and range of a list, and unpack the result.
  4. Show that a tuple containing a list can be modified in a limited way, and explain what the tuple still guarantees.
  5. Convert a list of three field tuples into namedtuples and sort them by the third field.

Conclusion

A tuple is an immutable sequence, and the comma is what creates it. Use it when the collection is a fixed record rather than a growing list, when you need a dictionary key, and when a function has several results to hand back.

Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All Python notes →
Python

Sorting Algorithms

Python sorts for you in n log n. Implementing bubble, insertion, merge and quick sort is still worth doing, because it teaches how algorithms are comp...

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.