Tuples
A tuple is an ordered collection of values, much like a list — but once created, it cannot be changed. That single difference, immutability, is what tuples are all about: it makes them safer to pass around, hashable enough to use as dictionary keys, and a natural fit for values that belong together and shouldn’t drift apart.
Creating a Tuple
You create a tuple with parentheses (or often no brackets at all) and commas separating the values.
point = (3, 4)
colors = ("red", "green", "blue")
mixed = ("Ada", 36, True)
# Parentheses are optional when the context is unambiguous
also_a_tuple = 3, 4
print(also_a_tuple) # (3, 4)
# Build a tuple from any iterable with tuple()
from_list = tuple([1, 2, 3])
print(from_list) # (1, 2, 3)
empty = ()
print(empty) # ()The Single-Element Tuple Gotcha
Parentheses alone don’t make a tuple — it’s the comma that does. Writing (1) just gives you the integer 1 wrapped in redundant parentheses. To create a one-item tuple you must include a trailing comma.
not_a_tuple = (1) print(type(not_a_tuple)) # <class 'int'> single_tuple = (1,) print(type(single_tuple)) # <class 'tuple'> print(single_tuple) # (1,) # The comma matters even without parentheses also_single = 1, print(type(also_single)) # <class 'tuple'>
Immutability: Why It Matters
Once a tuple is created, you cannot add, remove, or reassign any of its items. Attempting to do so raises a TypeError.
point = (3, 4) # point[0] = 99 # TypeError: 'tuple' object does not support item assignment # point.append(5) # AttributeError: 'tuple' object has no attribute 'append' print(point[0]) # 3 - reading is fine, only mutation is blocked
Immutability brings a few concrete, practical benefits.
Hashability — because a tuple’s contents can never change, Python can compute a stable hash for it, which means a tuple (of hashable items) can be used as a dictionary key or stored in a
set. A list cannot.Safety — if you pass a tuple into a function, you can be certain the function did not silently mutate your data. Passing a list gives no such guarantee.
Intent — using a tuple signals to other readers of your code “this is a fixed-size, fixed-shape record,” while a list signals “this collection may grow or shrink.”
Performance — tuples are slightly more memory-efficient and faster to create than lists, since Python doesn’t need to reserve room for future growth.
locations = {
(40.7128, -74.0060): "New York",
(51.5074, -0.1278): "London",
}
print(locations[(40.7128, -74.0060)]) # New York
# A list can't be used as a key:
# bad = {[1, 2]: "oops"} # TypeError: unhashable type: 'list'Tuple Packing and Unpacking
Writing several comma-separated values as one tuple is called packing. Pulling them back out into individual names is called unpacking — and it is one of the most useful tuple features in everyday Python.
# Packing: several values collapse into one tuple
point = 3, 4, 5
print(point) # (3, 4, 5)
# Unpacking: a tuple's values spread into separate names
x, y, z = point
print(x, y, z) # 3 4 5
# Swapping two variables without a temp variable
a, b = 1, 2
a, b = b, a
print(a, b) # 2 1
# Star-unpacking captures the "rest" into a list
first, *rest = (1, 2, 3, 4)
print(first, rest) # 1 [2, 3, 4]
# Functions that return multiple values are really returning a tuple
def min_max(numbers):
return min(numbers), max(numbers)
lo, hi = min_max([4, 1, 9, 3])
print(lo, hi) # 1 9Named Tuples
Plain tuples are accessed by position, which can get hard to read once you have more than two or three fields — person[1] doesn’t tell you much on its own. Named tuples solve this by letting you access fields by name while keeping all the performance and immutability benefits of a regular tuple.
The standard library offers two ways to create one: collections.namedtuple, a factory function, and typing.NamedTuple, a more modern class-based syntax with type hints.
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p.x, p.y) # 3 4
print(p[0], p[1]) # 3 4 - still works like a regular tuple
print(p) # Point(x=3, y=4)
x, y = p # unpacking still works too
print(x, y) # 3 4from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
p = Point(3, 4)
print(p.x, p.y) # 3 4
print(p) # Point(x=3, y=4)
# Still an immutable tuple under the hood
# p.x = 10 # AttributeError: can't set attributeTuple vs List: When to Use Which
Situation | Prefer |
|---|---|
Collection will grow or shrink over its lifetime | List |
Fixed-size “record” whose fields won’t change (e.g. a coordinate) | Tuple |
Needs to be used as a dict key or stored in a set | Tuple |
Returning multiple values from a function | Tuple |
You want to guarantee callers can’t mutate the data | Tuple |
Items need | List |
Homogeneous collection of similar items (usernames, scores) | List |
Heterogeneous, positional fields (name, age, email) | Tuple (ideally a named tuple) |