Two Ways to Walk a List
The same two loops as the strings chapter, over a list this time — and one new fact that changes everything. A string cannot be altered, so there the choice was only about knowing where you were. A list can be altered, and only one of the two loops is able to do it.
1The two loops, and their identical output
A list is a sequence, so a for loop hands out its items in order — exactly as it does with a string, only the items are whole values rather than single characters:
# the loop hands out one item at a time
marks = [56, 91, 43, 78]
for m in marks:
print(m)56 91 43 78
# the loop hands out one position at a time
marks = [56, 91, 43, 78]
for i in range(len(marks)):
print(marks[i])56 91 43 78
Identical output again, and the same real difference underneath: m holds the item — the number 56 — while i holds a position — the number 0 — and the item has to be fetched with marks[i].
# with the position, the item can be numbered
marks = [56, 91, 43, 78]
for i in range(len(marks)):
print('Student', i + 1, 'scored', marks[i])Student 1 scored 56 Student 2 scored 91 Student 3 scored 43 Student 4 scored 78
2The new question: can it change the list?
Here is a program that looks completely reasonable and does absolutely nothing. It is meant to give every student five grace marks:
# trying to raise every mark by 5, with the item form
marks = [10, 20, 30]
for m in marks:
m = m + 5
print(marks)[10, 20, 30]
And here is the same job, written with positions:
# the same job, with the index form
marks = [10, 20, 30]
for i in range(len(marks)):
marks[i] = marks[i] + 5
print(marks)[15, 25, 35]
m is a box of its own; marks[i] is a place in the list. The loop hands m a copy of each item, so m = m + 5 moves that box and the list is never told anything. marks[i] = … writes through the position, into the list itself. This is the same lesson as ch on a string — except that there, no loop could have changed the string, because a string cannot be changed at all.3Watch the list, three ways
Three programs, the same list, one round at a time. Watch the boxes underneath each one: on the left they never move, however many rounds go by.
Three programs, the same list, one round at a time. One of them does nothing at all.
Nothing has run yet. Watch the list below as the loop goes round.
Nothing has run yet. Watch the list below as the loop goes round.
Nothing has run yet. raised is an empty list, waiting to be filled.
append() leaves the original untouched, which is what you want when the old values still matter — and it is the only way to do it when the new list is a different length from the old one, as it is when you keep only the evens.4What actually differs
| by item | by index | |
|---|---|---|
| the header | for m in marks: | for i in range(len(marks)): |
| the loop variable holds | an item, 56 | a position, 0 |
| to use the item | m | marks[i] |
| knows its position? | no | yes |
| can change the list? | no | yes — marks[i] = … |
| can see the neighbours? | no | yes — marks[i + 1] |
5Recap
Shorter and enough for anything that only reads: totals, counts, tests, and building a second list.
The item costs one lookup, marks[i] — and in exchange you know where you are and can write back.
The loop variable is a copy in a box of its own. Everybody writes this program once; the list comes out exactly as it went in.
Do I need the position? And do I need to change the list? A yes to either one means the index form.
marks = [10, 20, 30]; for m in marks: m = m + 5. What does print(marks) show?
Which loop can print 'Student 3 scored 43'?
Which is the better way to build a list of only the even numbers from another list?