Skip to content

Latest commit

 

History

History
288 lines (207 loc) · 9.64 KB

File metadata and controls

288 lines (207 loc) · 9.64 KB

Python Tuples — Ordered, Immutable Sequences

📦 Meet the Tuple

A tuple is Python's second sequence type — an ordered collection of values, just like a list, but with one defining twist: it's immutable. Once you create a tuple, you can't change, add, or remove its items.

Big idea: if a list is a notepad you can edit, a tuple is a printed receipt. Same items, same order — but frozen in place. Use tuples for fixed collections that should never change after creation.

📝 Creating a Tuple — Literal Syntax

Use parentheses with comma-separated values (and yes, items can mix types):

developer = ('Alice', 34, 'Rust Developer')
numbers = (1, 2, 3, 4, 5)
empty = ()

💡 The Comma Is What Makes a Tuple

Parentheses alone don't create a tuple — the commas do. A single value in parens is just a grouped expression:

single = (42)       # ⚠️ This is an int, NOT a tuple!
real_single = (42,) # ✅ Tuple of one item — note the trailing comma
implicit = 1, 2, 3  # ✅ Also a tuple (parens are optional)

🧩 Tuple vs List — The Core Difference

Trait List Tuple
Syntax [1, 2, 3] (1, 2, 3)
Ordered? ✅ Yes ✅ Yes
Mutable? ✅ Yes — edit in place No — immutable
Zero-indexed? ✅ Yes ✅ Yes
Supports slicing? ✅ Yes ✅ Yes
Supports in? ✅ Yes ✅ Yes
Supports unpacking? ✅ Yes ✅ Yes
Usable as a dict key? ❌ No ✅ Yes (if items are hashable)
Memory & speed Slightly heavier Slightly lighter & faster

⚠️ Immutability — Why It Matters

Try to update a tuple and Python raises TypeError:

programming_languages = ('Python', 'Java', 'C++', 'Rust')
programming_languages[0] = 'JavaScript'
# TypeError: 'tuple' object does not support item assignment

And del on an index also fails:

developer = ('Jane Doe', 23, 'Python Developer')
del developer[1]
# TypeError: 'tuple' object doesn't support item deletion
flowchart TD
	TRY["You write code that<br>changes a tuple"] --> KIND{"What kind of change?"}
	KIND -- "tup[i] = x" --> ASSIGN["❌ TypeError<br>'tuple' object does not<br>support item assignment"]
	KIND -- "del tup[i]" --> DEL["❌ TypeError<br>'tuple' object doesn't<br>support item deletion"]
	KIND -- "tup.append(x)<br>tup.remove(x)" --> ATTR["❌ AttributeError<br>'tuple' object has no<br>attribute 'append'/'remove'"]
Loading
💡

Mental model: an immutable object is frozen — you can read it freely, but you can't rewrite it. To "change" a tuple, you create a new one.

🎯 Indexing — Same as Lists

Bracket notation with the index number:

developer = ('Alice', 34, 'Rust Developer')
developer[0]   # 'Alice'
developer[1]   # 34
developer[2]   # 'Rust Developer'

⬅️ Negative Indexing

numbers = (1, 2, 3, 4, 5)
numbers[-1]   # 5  ← last
numbers[-2]   # 4  ← second to last

⚠️ Out-of-Range → IndexError

numbers = (1, 2, 3, 4, 5)
numbers[7]
# IndexError: tuple index out of range

🏗️ The tuple() Constructor

Convert any iterable into a tuple:

developer = 'Jessica'
tuple(developer)        # ('J', 'e', 's', 's', 'i', 'c', 'a')

tuple([1, 2, 3])        # (1, 2, 3)        ← list → tuple
tuple(range(4))         # (0, 1, 2, 3)
tuple()                 # ()               ← empty tuple

Works with strings, lists, ranges, sets, dictionaries (gives the keys), and any other iterable.

🔍 Membership — The in Keyword

Identical to lists:

programming_languages = ('Python', 'Java', 'C++', 'Rust')

'Rust' in programming_languages         # True
'JavaScript' in programming_languages   # False
'JavaScript' not in programming_languages  # True

🎁 Unpacking — Same Pattern, Same Power

developer = ('Alice', 34, 'Rust Developer')
name, age, job = developer

print(name)  # 'Alice'
print(age)   # 34
print(job)   # 'Rust Developer'

✯ Star (*) — Catch the Remainder

developer = ('Alice', 34, 'Rust Developer')
name, *rest = developer

print(name)  # 'Alice'
print(rest)  # [34, 'Rust Developer']   ← always a LIST, even from a tuple
💡

Subtle but important: *rest always collects into a list, regardless of whether you unpacked a list, tuple, string, or any other iterable.

✂️ Slicing — Returns a New Tuple

Slicing a tuple gives you a brand-new tuple:

desserts = ('cake', 'pie', 'cookies', 'ice cream')
desserts[1:3]   # ('pie', 'cookies')

The start index is inclusive, the stop index is exclusive — same as lists.

desserts[:2]    # ('cake', 'pie')
desserts[2:]    # ('cookies', 'ice cream')
desserts[::-1]  # ('ice cream', 'cookies', 'pie', 'cake')   ← reversed copy

Slicing never raises IndexError — out-of-range stops are silently clipped, just like with lists.

🔀 When to Use a Tuple vs a List

flowchart TD
	Q["Need an ordered collection of values"] --> CHANGE{"Will the contents change<br>after creation?"}
	CHANGE -- Yes --> LIST["✅ Use a LIST<br>append, remove, sort, etc."]
	CHANGE -- No --> FIXED{"Is it a fixed record<br>(coords, RGB, db row)?"}
	FIXED -- Yes --> TUP["✅ Use a TUPLE<br>safe, hashable, faster"]
	FIXED -- No --> EITHER["Either works —<br>prefer tuple for safety"]
Loading

📦 Tuples shine when you have…

  • Fixed records — (latitude, longitude), (R, G, B), (year, month, day).
  • Multiple return values from a function: return min_val, max_val, average.
  • Dictionary keys that combine fields: prices[('USD', 'apple')] = 1.20.
  • Constants — a tuple of allowed colors, a tuple of HTTP method names, etc.
  • Performance — tuples are slightly smaller and faster to construct than lists.

📜 Lists shine when you need…

  • Growth — collecting items one at a time.
  • Mutation — sorting, removing, updating in place.
  • Open-ended sequences where the length isn't known up front.

🧬 Putting It All Together

# Create
point = (3, 7)              # a 2D coordinate (classic tuple use case)
rgb   = (255, 128, 0)       # an RGB color
langs = ('Python', 'Rust', 'Go')

# Read
print(point[0])             # 3
print(rgb[-1])              # 0

# Membership
print('Rust' in langs)      # True

# Unpack
x, y = point
print(x, y)                 # 3 7

r, *rest = rgb
print(r, rest)              # 255 [128, 0]

# Slice
print(langs[:2])            # ('Python', 'Rust')

# Convert
langs_list = list(langs)    # → ['Python', 'Rust', 'Go']
langs_list.append('Java')
langs = tuple(langs_list)   # → ('Python', 'Rust', 'Go', 'Java')

# Cannot mutate directly
try:
    langs[0] = 'JavaScript'
except TypeError as e:
    print(e)                # 'tuple' object does not support item assignment

🎯 Best Practices

  • ✅ Reach for a tuple when the data is a fixed record (coords, RGB, DB row) that shouldn't change.
  • ✅ Use tuples to return multiple values from functions — unpack at the call site.
  • ✅ Use tuples as dictionary keys when you need a composite key (lists won't work — they're unhashable).
  • ✅ Remember the trailing comma for one-item tuples: (42,).
  • ✅ Convert with list(t) and tuple(l) when you need to switch between mutability and immutability temporarily.
  • ✅ Document tuple structures with comments or namedtuple / dataclass for clarity — you'll meet these later.

⚠️ Common Mistakes to Avoid

  • (42) is not a tuple. Use (42,) for a single-item tuple.
  • ❌ Trying to assign to or delete an index → TypeError. Tuples are immutable.
  • ❌ Calling tup.append(x) or tup.remove(x)AttributeError. Those are list methods.
  • ❌ Forgetting that slicing returns a new tuple — the original is untouched (but it never could change anyway).
  • ❌ Using a list where a tuple would be safer for fixed records — you lose the "don't change me" guarantee.
  • ❌ Trying to use a list as a dictionary key — only tuples of hashable items work.

❓ Quick Self-Check

  • What will be output by print(developer[1]) for developer = ('Alice', 34, 'Rust Developer')?34
  • What is desserts[1:3] for desserts = ('cake', 'pie', 'cookies', 'ice cream')?('pie', 'cookies')
  • What happens with del developer[1] on a tuple?You will get a TypeError.

✅ Key Takeaways

  • A tuple is an ordered, immutable, zero-indexed sequence — lists' frozen cousin.
  • Create with ( ... ) or tuple(iterable). One-item tuples need a trailing comma: (42,).
  • Supports indexing, negative indexing, slicing, in, and unpacking — just like lists.
  • Cannot be modified after creation: assignment, deletion, append, remove all error out.
  • Use tuples for fixed records, multiple return values, dictionary keys, and safer constants.
  • Use lists when you need to grow or mutate the collection.
  • Slicing returns a new tuple; *rest always collects into a list.
  • Next up: tuple methods — the small but useful built-ins (count(), index()) plus a closer look at key= and reverse= in sorting.

➡️

Next chapter → Python Tuple Methods — count, index & sorted()

Tuples ship with just two read-only methods — count() and index(). Pair them with the built-in sorted(), plus its key and reverse options, to do real work with immutable sequences.