LambdaLabTM
Computer Science · Class 11 · Tuples Revisited
TuplesTraversal⏱️ 12 min read

Two Ways to Walk a Tuple

The same two loops as strings and lists, over a tuple this time. What is different is the ending. On a list, the index form earned its keep because it was the only one that could change the list. A tuple cannot be changed by either form — so on this page the index form is only ever about knowing where you are, and “change it” turns into build a new one.

1The two loops, and their identical output

A tuple is a sequence, so a for loop hands out its items in order, exactly as it does for a list:

by_item.py
# the loop hands out one item at a time

colours = ('red', 'green', 'blue')

for c in colours:
    print(c)
Output
red
green
blue
by_index.py
# the loop hands out one position at a time

colours = ('red', 'green', 'blue')

for i in range(len(colours)):
    print(colours[i])
Output
red
green
blue

Identical output, and the same real difference underneath: c holds the item — the string 'red' — while i holds a position — the number 0 — and the item has to be fetched with colours[i].

Key Takeaway
The question is: do you need to know where you are? Adding prices up does not need the position. Printing a numbered menu does. That is the entire choice on a tuple, because the second reason — being able to write back — is not available here at all.

2What the position is actually for

The index form is worth having whenever the output has to mention which item this is:

numbered.py
# a numbered menu needs the position, not just the item

colours = ('red', 'green', 'blue')

for i in range(len(colours)):
    print(str(i + 1) + '.', colours[i])
Output
1. red
2. green
3. blue

i + 1 because the reader counts from 1 and Python counts from 0, and str(i + 1) + '.' so the number and the full stop are glued together with no space between them — print(i + 1, '.', colours[i]) would print 1 . red, with the gap in the wrong place.

3Neither loop can change a tuple

On a list, this was the program that made the index form necessary — give every student five grace marks. On a tuple it does not run at all:

grace_fails.py
# trying to raise every mark by 5, in a tuple

marks = (10, 20, 30)

for i in range(len(marks)):
    marks[i] = marks[i] + 5

print(marks)
Output
Traceback (most recent call last):
  File "grace_fails.py", line 6, in <module>
    marks[i] = marks[i] + 5
    ~~~~~^^^
TypeError: 'tuple' object does not support item assignment
Watch Out
This is not a fault in the loop — it is what a tuple is. The item form for m in marks: m = m + 5 does not raise anything, but it does not work either: it just changes the loop variable and leaves the tuple alone, exactly as it did on a list. So one form crashes and the other quietly does nothing, and neither is the answer.

4So build a second tuple

A locked box cannot be edited, but nothing stops you from filling a second box. The collector starts as an empty tuple (), and each round sticks one more item on the end:

grace.py
# the tuple cannot be changed, so build a new one

marks = (10, 20, 30)
raised = ()

for m in marks:
    raised = raised + (m + 5,)

print('Original:', marks)
print('Raised:  ', raised)
Output
Original: (10, 20, 30)
Raised:   (15, 25, 35)
Watch Out
That comma in (m + 5,) is doing real work. (15) is just the number 15 in brackets, and Python refuses to join a number onto a tuple:
TypeError: can only concatenate tuple (not "int") to tuple
(15,) — with the comma — is a one-item tuple, and joining tuple to tuple is fine. The comma is what makes it a tuple, not the brackets.

raised = raised + (m + 5,) is the tuple version of squares.append(...). It reads the same way and it does something slightly different underneath: append adds to the list you already have, while + builds a brand new tuple each round and points raised at it. For the twenty items a Class 11 program handles, that difference costs nothing.

grace.py

5The collectors, unchanged

Everything the lists chapter taught about collectors still applies — reading a tuple is exactly like reading a list:

total.py
# adding up a tuple is the same loop as adding up a list

prices = (250, 120, 480, 90)
total = 0

for p in prices:
    total = total + p

print('Total:', total)
Output
Total: 940
Total
total = 0

Adds each item. Zero is the value that changes nothing.

Count
count = 0

Goes up by 1 when the item passes a test — by 1, not by the item.

Champion
best = marks[0]

The best seen so far. Starts as a real member of the tuple.

New tuple
result = ()

Grows by result = result + (x,). The original is never touched — it cannot be.

6Recap

Both loops print the same thing

for c in colours hands you the item; for i in range(len(colours)) hands you the position and colours[i] fetches the item.

Use the index form when the output names the position

A numbered list, a 'found at index 3' message. Otherwise the item form is shorter and harder to get wrong.

Neither form can change a tuple

marks[i] = ... is a TypeError; m = ... changes only the loop variable. On a tuple this is not a choice you have.

Build a second tuple instead

raised = () above the loop, raised = raised + (x,) inside it. The comma is what makes (x,) a tuple.

✍️ Now write these yourself
  1. 1

    Print every colour in a tuple in capitals, one per line, without changing the tuple.

    Hint · for c in colours: and print(c.upper()). Printing in capitals is not changing anything.

  2. 2

    Print a tuple of subjects as a numbered list.

    Hint · The index form, and i + 1 so the first line says 1.

  3. 3

    Build a second tuple holding the double of every number in the first.

    Hint · doubles = () above the loop, then doubles = doubles + (n * 2,) inside it.

  4. 4

    Build a tuple holding only the even numbers from another tuple.

    Hint · Same shape, with the join inside an if n % 2 == 0:. The new tuple comes out shorter.

  5. 5

    Add up the lengths of all the words in a tuple of names.

    Hint · A total, going up by len(name) rather than by the name.

Quick Check

Why does marks[i] = marks[i] + 5 fail on a tuple?

Quick Check

What is wrong with raised = raised + (m + 5)?

Quick Check

When is the index form worth choosing on a tuple?