Technology  /  Python

🐍 Python 78 guides · updated 2026

From first variable to OOP, generators, and real projects — the language that runs everything from data pipelines to AI agents, taught the practical way.

Python Tuples: When Immutability Is the Right Choice

The most common description of tuples — “they’re like lists but immutable” — is accurate but undersells them. Tuples are the right tool in specific situations, and using a list when a tuple is appropriate is like using a screwdriver when a wrench is called for. Both turn the fastener, but one fits.


What a Tuple Is

A tuple is an ordered, immutable sequence. Once created, its contents cannot be changed. Tuples use parentheses, though the parentheses are often optional:

coordinates = (40.7128, -74.0060)
dimensions = (1920, 1080)
single_element = (42,) # the trailing comma is required for single-element tuples
also_a_tuple = 1, 2, 3 # parentheses optional — this is tuple packing
empty = ()

The trailing comma for single-element tuples is a genuine gotcha. Without it, Python interprets (42) as just the integer 42 in parentheses:

print(type((42))) # <class 'int'>
print(type((42,))) # <class 'tuple'>

Accessing Tuple Elements

Tuples support all the same indexing and slicing operations as lists:

rgb = (255, 128, 0)
print(rgb[0]) # 255
print(rgb[-1]) # 0
print(rgb[0:2]) # (255, 128)
# Iteration
for channel in rgb:
print(channel)
# Membership
print(255 in rgb) # True

What tuples don’t support is modification:

rgb[0] = 100 # TypeError: 'tuple' object does not support item assignment

Tuple Unpacking

Unpacking assigns tuple elements to variables in a single statement. It’s one of Python’s most elegant features:

point = (3, 7)
x, y = point
print(f"x={x}, y={y}") # x=3, y=7
# Function returning multiple values uses tuple packing/unpacking
def min_max(numbers):
return min(numbers), max(numbers) # returns a tuple
low, high = min_max([5, 3, 8, 1, 9])
print(f"Low: {low}, High: {high}") # Low: 1, High: 9

Extended unpacking with *

The * operator collects multiple elements into a list:

first, *middle, last = (1, 2, 3, 4, 5)
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5
# Ignore values you don't need with _
_, second, *_ = (10, 20, 30, 40)
print(second) # 20

Swapping variables

Tuple unpacking makes swapping values trivially clean:

a, b = 10, 20
a, b = b, a # swap without a temp variable
print(a, b) # 20 10

Why Tuples Over Lists?

Semantic meaning

When you return coordinates, RGB values, a name/age pair, or any fixed collection of related values, a tuple signals “these go together and they won’t change.” A list says “here’s a collection that might grow or shrink.” The type choice communicates intent.

Tuples as dictionary keys

Lists cannot be dictionary keys because they’re mutable (and therefore not hashable). Tuples can:

grid = {}
grid[(0, 0)] = "origin"
grid[(1, 0)] = "east"
grid[(0, 1)] = "north"
print(grid[(0, 0)]) # "origin"
# Useful for 2D coordinates, chess positions, graph edges
visited = {(0, 0), (1, 0), (0, 1)} # set of coordinate tuples

Slightly faster than lists

Tuples have lower memory overhead and slightly faster iteration than equivalent lists, because Python can make assumptions about their unchangeable contents. For most code this difference is negligible, but it matters in tight loops over millions of elements.

Structural pattern matching (Python 3.10+)

Tuples work naturally with Python’s match statement for pattern matching on structure:

def describe_point(point):
match point:
case (0, 0):
return "Origin"
case (x, 0):
return f"On x-axis at {x}"
case (0, y):
return f"On y-axis at {y}"
case (x, y):
return f"Point at ({x}, {y})"

Named Tuples

Regular tuples require remembering what each position means. namedtuple from the collections module gives positions descriptive names:

from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
Color = namedtuple("Color", ["red", "green", "blue"])
p = Point(3, 7)
print(p.x) # 3 — access by name
print(p[0]) # 3 — still works by index
print(p) # Point(x=3, y=7) — clear repr
pixel = Color(255, 128, 0)
print(f"Red channel: {pixel.red}")

Named tuples are immutable like regular tuples but far more readable. They’re also memory-efficient compared to dictionaries.

Python 3.6+ alternative: dataclasses

For more complex use cases with methods and mutability options, dataclasses.dataclass with frozen=True is the modern equivalent:

from dataclasses import dataclass
@dataclass(frozen=True)
class Point:
x: float
y: float
p = Point(3.0, 7.0)
print(p.x) # 3.0
p.x = 1.0 # FrozenInstanceError

Common Pitfalls

Tuple with mutable contents. The tuple itself is immutable, but if it contains a list, that list can still be modified:

t = ([1, 2], [3, 4])
t[0].append(99) # works — modifying the list, not the tuple
print(t) # ([1, 2, 99], [3, 4])
t[0] = [] # TypeError — can't replace the reference

Accidentally creating a tuple instead of a grouping. Python’s tuple packing is automatic, which can cause confusion in return statements:

def get_data():
return 1, 2 # returns the tuple (1, 2), not two separate values
data = get_data()
print(data) # (1, 2)
print(type(data)) # <class 'tuple'>

Use tuples when data is structurally fixed and related. Use lists when data is a collection that might grow, shrink, or be sorted.