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:
# the loop hands out one item at a time
colours = ('red', 'green', 'blue')
for c in colours:
print(c)red green blue
# the loop hands out one position at a time
colours = ('red', 'green', 'blue')
for i in range(len(colours)):
print(colours[i])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].
2What the position is actually for
The index form is worth having whenever the output has to mention which item this is:
# 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])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:
# 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)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 assignmentfor 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:
# 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)Original: (10, 20, 30) Raised: (15, 25, 35)
(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.
5The collectors, unchanged
Everything the lists chapter taught about collectors still applies — reading a tuple is exactly like reading a list:
# 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)Total: 940
total = 0Adds each item. Zero is the value that changes nothing.
count = 0Goes up by 1 when the item passes a test — by 1, not by the item.
best = marks[0]The best seen so far. Starts as a real member of the tuple.
result = ()Grows by result = result + (x,). The original is never touched — it cannot be.
6Recap
for c in colours hands you the item; for i in range(len(colours)) hands you the position and colours[i] fetches the item.
A numbered list, a 'found at index 3' message. Otherwise the item form is shorter and harder to get wrong.
marks[i] = ... is a TypeError; m = ... changes only the loop variable. On a tuple this is not a choice you have.
raised = () above the loop, raised = raised + (x,) inside it. The comma is what makes (x,) a tuple.
- 1
Print every colour in a tuple in capitals, one per line, without changing the tuple.
Hint ·
for c in colours:andprint(c.upper()). Printing in capitals is not changing anything. - 2
Print a tuple of subjects as a numbered list.
Hint · The index form, and
i + 1so the first line says 1. - 3
Build a second tuple holding the double of every number in the first.
Hint ·
doubles = ()above the loop, thendoubles = doubles + (n * 2,)inside it. - 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
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.
Why does marks[i] = marks[i] + 5 fail on a tuple?
What is wrong with raised = raised + (m + 5)?
When is the index form worth choosing on a tuple?