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.
- Basics
- Data Types
- Operators
- Strings
- Control Flow
- Lists
- Tuples
- Sets
- Dictionaries
- Comprehensions
- Functions
- Advanced Functions
- Recursion
- Exception Handling
- File Handling
- Modules
- Standard Library
- OOP
- Advanced OOP
- Iterators and Generators
- Decorators
- Context Managers
- Descriptors and Dataclasses
- Python Internals
- Concurrency
- Regular Expressions
- Serialization
- Command Line Python
- Testing and Debugging
- Type Hints
- Performance
- Python Security
- DSA with Python
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 tupleOnly 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) # TrueImmutable 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?
| Tuple | List | |
|---|---|---|
| Changeable | No | Yes |
| As a dictionary key | Yes | No |
| In a set | Yes | No |
| Memory | Slightly less | Slightly more |
| Creation speed | Slightly faster | Slightly slower |
| Typical meaning | One record with fixed fields | Many 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 measurementA 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")]) # 150This 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]) # 3A 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) # MeeraCommon 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
namedtupleonce 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
- Explain why
len((5))raises butlen((5,))is1. - Build a dictionary that stores a value for every cell of a 3 by 3 board using tuple keys.
- Write a function returning the minimum, maximum and range of a list, and unpack the result.
- Show that a tuple containing a list can be modified in a limited way, and explain what the tuple still guarantees.
- 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.