A string is a row of characters. A list is a row of anything: numbers, strings, a mixture. Most of what you learned about strings carries straight over, with one large difference: a list can be changed after it is made. It can grow, shrink and have its items replaced, and that is what makes it the everyday container of Python.
Before this, you can: index and slice a string; loop over the characters of a string; keep a best-so-far value in a loop.
By the end you will be able to read and replace items by position, loop over a list, add and remove items, build a new list in a loop, choose between looping over the items and looping over the positions, and move between text and a list of words.
Before you read on, decide what this prints:
numbers = [1, 2, 2, 3]
for n in numbers:
if n == 2:
numbers.remove(n)
print(numbers)
[1, 2, 3]
One of the two 2s is still there. Nothing warned you, and the loop looks right. Removing from a list while a loop is walking along it makes the loop skip the item after each removal. The lesson returns to this at the end of "Adding and removing", once you have the pieces to see why.
A list is written with square brackets and commas. Positions, negative positions, len and slices work exactly as they do for strings:
scores = [70, 85, 60, 92]
print(scores[0], scores[-1], len(scores))
print(scores[1:3])
70 92 4
[85, 60]
A slice of a list is a new list. It is a copy of that part: replacing, adding or removing items in the copy leaves the original alone. (That is the whole story for lists of numbers and text, like these. A list that holds other lists needs more care, which is the next module.)
There is no fixed size and no declared type. A list is as long as what is in it, and [] is a list with nothing in it yet.
Here is the difference from strings. An item of a list can be replaced:
scores = [70, 85, 60, 92]
scores[1] = 0
print(scores)
[70, 0, 60, 92]
No new list was made. The list that scores names now holds something different at position 1. Try the same on a string and Python refuses:
word = "cat"
word[1] = "x"
File "your_program.py", line 2
word[1] = "x"
TypeError: 'str' object does not support item assignment
This is why string methods hand back a new string, and why, as you will see in a moment, list methods mostly do not.
A for loop walks along a list just as it walks along a string. The loop variable is given each item in turn:
scores = [70, 85, 60]
total = 0
for score in scores:
total = total + score
print(total)
215
This is the normal way to loop over a list in Python. There is no position to manage and no way to run off the end.
The items can be drawn as easily as added up:
from scimigo import canvas, rectangle
canvas(600, 400)
scores = [70, 85, 60, 92]
x = 40
for score in scores:
rectangle(x, 350 - score * 3, 50, score * 3, color="steelblue")
x = x + 70
The loop variable gives the height of each bar. The position across the page is kept in x, which moves along by 70 on every turn.
append adds an item at the end. pop takes the last item out and hands it back:
stack = [1, 2]
stack.append(3)
last = stack.pop()
print(stack, last)
[1, 2] 3
Notice that stack.append(3) stands on a line of its own, with no stack = in front. Both methods change the list itself, which is the opposite of string methods. They differ in what they hand back: pop hands back the item it took out, which is why its result is kept in last, while append hands back None. So writing stack = stack.append(3) is a classic mistake: stack would stop being a list.
pop(0) takes out the first item, and insert(0, value) puts one in at the front. in asks whether a value is in the list, and remove takes out the first item equal to a value. Like append, both insert and remove hand back None:
items = [3, 5, 3, 8]
print(5 in items)
items.remove(3)
print(items)
items.insert(0, 9)
print(items)
True
[5, 3, 8]
[9, 5, 3, 8]
Only the first 3 went. Asking remove for a value that is not there is an error, so test with in first if you are not sure.
Now the puzzle from the top of the page. A for loop over a list keeps a position inside itself: first item 0, then item 1, and so on. Follow it through [1, 2, 2, 3]:
[1, 2, 3]. Everything after it has moved one place to the left;So the loop never looks at the second 2. The rule to take away: do not add to or remove from a list while a loop is walking along it. Build a new list instead, which is the next section.
To make a list from a calculation, start with an empty one and append in a loop. It is the same pattern as a running total, and as building a string:
squares = []
for n in range(1, 6):
squares.append(n * n)
print(squares)
[1, 4, 9, 16, 25]
The same pattern picks out some items of another list, by putting the append under an if:
numbers = [4, -1, -2, 7]
kept = []
for n in numbers:
if n >= 0:
kept.append(n)
print(kept, numbers)
[4, 7] [4, -1, -2, 7]
numbers is untouched, and kept holds the ones that passed. This is the safe way to "remove" items: keep the ones you want.
for item in items gives you the items and hides their positions. Sometimes the position is what you are after: which place holds the largest value, or which two neighbours are equal. Then loop over the positions and look each item up:
scores = [70, 85, 60, 92]
best = 0
for i in range(len(scores)):
if scores[i] > scores[best]:
best = i
print(best, scores[best])
3 92
best holds a position here, not a score. The same loop is what you need to change the items of a list, because giving a new value to the loop variable of for score in scores changes only that variable, as with the parameter in Functions.
Choose the plain loop when the items are enough, and the position loop when you need to know where you are.
Two string methods connect text and lists. split cuts a string into a list of words wherever there are spaces, however many. join goes the other way: it is called on the text to put between the items.
words = "red green blue".split()
print(words)
print(len(words))
print("-".join(words))
['red', 'green', 'blue']
3
red-green-blue
join needs a list of strings. A list of numbers has to be turned into strings first.
You will read items and slices, replace an item, draw a scoreboard with a bar for every score, follow a list through append, pop and remove, collect results in a new list, choose the right loop for a question, and then write functions that find the largest value by hand and pick out the scores above the average.