Mathew K Analytics

Lesson 7 · Python data types deep dive

Python Tuples Explained: Immutable, Fast & Unpackable | Data Types #7

Video seven of the twelve-part series: tuple, list's immutable cousin. Only two public methods, but a surprising amount of genuinely important behavior…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Python Data Types Deep-Dive, Video 7: Tuples (tuple)#

  • Video seven of the twelve-part series: tuple, list's immutable cousin.
  • Only two public methods, but a surprising amount of genuinely important behavior around unpacking, hashability, and named tuples.
  • Let's get into it.

Part 1: What Makes tuple Different#

point = (3, 4)
print(type(point))
print(len(point))
print(point[0], point[1])
try:
    point[0] = 99
except TypeError as e:
    print(f'Caught: {e}')
<class 'tuple'>
2
3 4
Caught: 'tuple' object does not support item assignment

Part 2: Tuple Literals and Construction#

with_parens = (1, 2, 3)
without_parens = 1, 2, 3
print(with_parens == without_parens)
not_a_tuple = (5)
print(type(not_a_tuple))
genuine_single = (5,)
print(type(genuine_single))
also_single = 5,
print(type(also_single))
True
<class 'int'>
<class 'tuple'>
<class 'tuple'>
empty = ()
also_empty = tuple()
from_list = tuple([1, 2, 3])
from_string = tuple('abc')
from_range = tuple(range(5))
print(empty, also_empty, from_list, from_string, from_range)
() () (1, 2, 3) ('a', 'b', 'c') (0, 1, 2, 3, 4)

Part 3: Indexing and Slicing#

letters = ('a', 'b', 'c', 'd', 'e')
print(letters[0])
print(letters[-1])
print(letters[1:4])
print(type(letters[1:4]))
print(letters[::-1])
a
e
('b', 'c', 'd')
<class 'tuple'>
('e', 'd', 'c', 'b', 'a')

Part 4: The Two Methods: count and index#

numbers = (10, 20, 30, 20, 40, 20)
print(numbers.count(20))
print(numbers.count(99))
print(numbers.index(30))
print(numbers.index(20))
print(numbers.index(20, 3))
try:
    numbers.index(999)
except ValueError as e:
    print(f'Caught: {e}')
3
0
2
1
3
Caught: tuple.index(x): x not in tuple

Part 5: Immutability in Practice#

record = ('Ana', [85, 90, 78])
record[1].append(95)
print(record)
try:
    record[1] = [100]
except TypeError as e:
    print(f'Caught: {e}')
('Ana', [85, 90, 78, 95])
Caught: 'tuple' object does not support item assignment
a = (1, 2, 3)
b = (1, 2, 3)
print(a == b)
print(a is b)
print(hash(a) == hash(b))
combined = a + b
print(combined)
repeated = a * 3
print(repeated)
True
False
True
(1, 2, 3, 1, 2, 3)
(1, 2, 3, 1, 2, 3, 1, 2, 3)

Part 6: Tuple Packing and Unpacking#

point = (3, 4, 5)
x, y, z = point
print(x, y, z)
a, b = 10, 20
print(a, b)
a, b = b, a
print(a, b)
3 4 5
10 20
20 10
first, *middle, last = (1, 2, 3, 4, 5)
print(first, middle, last)
head, *rest = (1, 2, 3, 4)
print(head, rest)
*rest, tail = (1, 2, 3, 4)
print(rest, tail)
1 [2, 3, 4] 5
1 [2, 3, 4]
[1, 2, 3] 4

Part 7: Tuples as Multiple Return Values#

def min_max(numbers):
    return min(numbers), max(numbers)
result = min_max([4, 1, 7, 3, 9])
print(result)
print(type(result))
lowest, highest = min_max([4, 1, 7, 3, 9])
print(lowest, highest)
(1, 9)
<class 'tuple'>
1 9

Part 8: Tuples as Dictionary Keys#

distances = {}
distances[(0, 0)] = 0
distances[(3, 4)] = 5
distances[(1, 1)] = 1.41
print(distances)
print(distances[(3, 4)])
try:
    bad = {[1, 2]: 'value'}
except TypeError as e:
    print(f'Caught: {e}')
{(0, 0): 0, (3, 4): 5, (1, 1): 1.41}
5
Caught: unhashable type: 'list'

Part 9: Named Tuples#

from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
print(p)
print(p.x, p.y)
print(p[0], p[1])
print(isinstance(p, tuple))
px, py = p
print(px, py)
Point(x=3, y=4)
3 4
3 4
True
3 4

Part 10: Tuple vs List, When to Use Which#

import sys
list_version = [1, 2, 3, 4, 5]
tuple_version = (1, 2, 3, 4, 5)
print(sys.getsizeof(list_version))
print(sys.getsizeof(tuple_version))
import timeit
list_time = timeit.timeit('[1, 2, 3, 4, 5]', number=1000000)
tuple_time = timeit.timeit('(1, 2, 3, 4, 5)', number=1000000)
print(f'List construction: {list_time:.3f}s')
print(f'Tuple construction: {tuple_time:.3f}s')
104
80
List construction: 0.034s
Tuple construction: 0.007s

Part 11: Common Patterns and Pitfalls#

def get_status():
    return ('ready')
result = get_status()
print(type(result))
def get_status_fixed():
    return ('ready',)
fixed_result = get_status_fixed()
print(type(fixed_result))
<class 'str'>
<class 'tuple'>
rows = [(1, 'a'), (2, 'b'), (3, 'c')]
combined = ()
for row in rows:
    combined += row
print(combined)
flattened = tuple(value for row in rows for value in row)
print(flattened)
print(combined == flattened)
(1, 'a', 2, 'b', 3, 'c')
(1, 'a', 2, 'b', 3, 'c')
True

Wrap-Up: What You Learned#

  • tuple is an ordered, immutable sequence; both public methods, count and index, are read-only.
  • Literal syntax, the comma-makes-a-tuple rule, and the single-element trailing-comma trap.
  • Indexing, slicing, immutability, and how mutable elements inside a tuple can still change.
  • Packing and unpacking, including starred catch-all unpacking and the classic swap idiom.
  • Multiple return values, hashability, tuples as dictionary keys, and named tuples for readable fields.
  • When to reach for tuple over list, and two common pitfalls to avoid.
  • That's both public tuple methods covered, plus everything around them. Next up: dict, Python's key-value workhorse.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.