Why immutability buys you a dictionary key
A dictionary key has to be hashable, which in practice means it must never change — if it changed, the dictionary would look for it in the wrong place. Lists are mutable, so they are unhashable, so they cannot be keys. Tuples can.
grid[(2, 3)] = "wall"
That is how you key anything by a coordinate pair, a date triple, or any other small fixed group.
Unpacking is the point
Unpacking assigns each position to a name in one statement:
x, y = point
It is not a special tuple feature — it works on any sequence — but tuples are where you meet it. The number of names must match the number of items, or Python raises ValueError, which is a feature: it catches the case where the shape you expected is not the shape you got.
The swap idiom falls straight out of it:
a, b = b, a
The right-hand side is evaluated first, into a tuple, and only then unpacked. No temporary variable, and no ordering bug.
Returning more than one thing
Python has no special syntax for multiple return values because it does not need any. return min(xs), max(xs) returns a tuple, and the caller unpacks it:
low, high = min_max(values)
This reads better than returning a list, because the shape is fixed: exactly two things, in a known order.
The comma is the tuple
The most common surprise is that brackets do not make a tuple — commas do.
type((5)) # int
type((5,)) # tuple
A single-element tuple needs the trailing comma. It looks like a typo and is not. This bites when a function is supposed to return one item as a tuple and quietly returns the item instead.
When to reach for which
Use a list when the collection will grow, shrink or be sorted in place. Use a tuple when the group is fixed at creation and its positions mean something: a coordinate, an RGB colour, a row from a database. If you find yourself never mutating a list, a tuple states that intent and gets you hashability for free.