The idea
A tuple is like a list that can't be changed. It's an ordered group of values, written with round brackets:
location = (-6.2088, 106.8456) # latitude, longitude of Jakarta
order = ("NG-24107", "2024-09-15", 798000)
print(location[0])
print(order[-1])
print(len(order))
-6.2088
798000
3
Indexing, negative indexes, slicing and len() all work exactly as with lists. What you can't do is change a tuple once it exists:
order[2] = 800000
TypeError: 'tuple' object does not support item assignment
So why would you want a list that's missing features? Because "this can't change" is a promise, and promises make code easier to trust.
A list is a shopping list on a whiteboard: you keep adding and crossing off. A tuple is a printed receipt: it records exactly what happened, and nobody should edit it afterwards.
Lists versus tuples
The rule of thumb used by experienced Python programmers:
- Use a list for a collection of similar things that may grow or shrink: all orders, all prices, a queue.
- Use a tuple for a fixed record of related values, where each position means something different: a (latitude, longitude) pair, an (order_id, date, total) record, an RGB colour like
(86, 105, 253).
In a list, every item plays the same role. In a tuple, position 0 might be a name, position 1 a city and position 2 an amount. That's why tuples are often described as "lightweight records".
| List | Tuple | |
|---|---|---|
| Syntax | [1, 2, 3] | (1, 2, 3) |
| Can change? | Yes (mutable) | No (immutable) |
| Typical use | many items of one kind | one record of a few fields |
| Methods | many (append, sort…) | just count and index |
Creating tuples
The brackets are actually optional. It's the commas that make a tuple:
point = 3, 4
print(type(point))
single = ("Jakarta",)
not_a_tuple = ("Jakarta")
print(type(single), type(not_a_tuple))
<class 'tuple'>
<class 'tuple'> <class 'str'>
A one-item tuple needs a trailing comma: ("Jakarta",). Without it, the brackets are just ordinary grouping brackets and you get a plain string. You'll rarely need a one-item tuple, but now you won't be confused when you see one.
You can turn a list into a tuple with tuple(), and back with list():
cities = ["Jakarta", "Bandung"]
frozen = tuple(cities)
print(frozen)
print(list(frozen))
('Jakarta', 'Bandung')
['Jakarta', 'Bandung']
Unpacking: the real superpower
Unpacking assigns each item of a tuple to its own variable in one line. You already used it for swapping in the variables module; now you can see what was happening:
order = ("NG-24107", "2024-09-15", 798000)
order_id, date, total = order
print(order_id)
print(total)
NG-24107
798000
The number of names on the left must match the number of items. Unpacking turns order[2] (what was index 2 again?) into total, which explains itself.
If you only need some of the values, the convention is to use _ for the ones you're ignoring, and * to collect "the rest" into a list:
order_id, _, total = order
print(order_id, total)
first, *others = ["Ayu", "Budi", "Citra", "Dimas"]
print(first)
print(others)
NG-24107 798000
Ayu
['Budi', 'Citra', 'Dimas']
Returning several values
Tuples appear whenever a piece of code hands back more than one value. Python's built-in divmod() returns the floor division and the remainder together, as a tuple:
result = divmod(135, 60)
print(result)
hours, minutes = divmod(135, 60)
print(f"{hours} h {minutes} min")
(2, 15)
2 h 15 min
When you write your own functions in a later module, you'll return tuples the same way, and the caller will unpack them.
Tuples as dictionary keys and set members
Because tuples can't change, Python can use them in places where lists aren't allowed, such as dictionary keys and set items (both coming up next). For example, a dictionary of delivery fees keyed by (from_city, to_city) pairs is natural with tuples and impossible with lists.
route = ("Jakarta", "Bandung")
print(hash(route) == hash(("Jakarta", "Bandung")))
True
The technical word is hashable: Python can compute a fixed fingerprint (a hash) for the value because it never changes. Lists are not hashable, since their contents could change after the fingerprint was taken.
A tuple is only as frozen as its contents. A tuple containing a list, like (1, [2, 3]), can't have its items reassigned, but the list inside can still be changed. Keep tuples made of simple values (numbers, strings, other tuples) and they behave as you'd expect.
Why this matters for clean code
Choosing a tuple tells the next reader "this group of values belongs together and won't change". That's information they don't have to work out. Combined with unpacking (order_id, date, total = order), tuples let you give every value a meaningful name at the moment you use it, instead of scattering mystery indexes like row[2] through your code.
Recap
- A tuple is an ordered, immutable group:
(a, b, c). Commas make it, brackets are optional. - Indexing, slicing and
len()work; changing items raisesTypeError. - Lists for collections of similar things; tuples for fixed records of related values.
- Unpack with
a, b, c = some_tuple. Use_for values you ignore and*restto collect extras. - Functions like
divmod()return tuples. Tuples can be dictionary keys; lists can't.