On this page

Lists

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.

Many values, one name

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.

Lists can change

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.

Every item in turn

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.

Adding and removing

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]:

  • position 0 is 1: nothing happens;
  • position 1 is 2: it is removed, and the list is now [1, 2, 3]. Everything after it has moved one place to the left;
  • position 2 is now 3. The second 2 has slid into position 1, which the loop has already passed.

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.

Building a list

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.

When you need the position

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.

Words to a list, and back

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.

In the lab

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.

Your turn

Now try it yourself

Predict what a program will do, run it, and step through it line by line. The checks tell you when your own code works.

Loading the lab…

In this lab

  1. Index and length

    Positions, negative positions, len and slices work on a list as they do on a string. Decide what each line prints.

  2. It changes

    Three short programs about what can be changed and what a change touches. Decide what each one does.

  3. Scoreboard

    This program draws one bar, for the first score. Change it so that it draws a bar for every score in the list, however many there are.

    • The first bar is at x = 40, and each bar is 70 further right than the one before.
    • A bar is 50 wide and 3 times its score tall, coloured "steelblue", with its bottom edge at y = 350.
    • Under each bar its score is written, at 8 to the right of the bar's x and at y = 375.

    The checks try lists of other lengths.

  4. In and out

    append adds at the end. pop takes an item out and hands it back: the last one, or the one at the position you give. Follow the list through each line, then decide what is printed.

  5. Is it there? Take it out

    in asks whether a value is in a list. remove takes out the first item equal to a value. This list has a 3 in it twice. One line of the program fails.

  6. Collect the squares

    This program prints the squares of the numbers from 1 to count, one per line. Change it so that it collects them in a list named squares and prints that list once, after the loop.

    For count = 6 the output is the single line [1, 4, 9, 16, 25, 36].

  7. Position or value?

    There are two ways to loop over a list: over its items, or over its positions. Decide what each program prints, and which loop a task needs.

  8. Words to a list, and back

    split cuts a string into a list of words. join puts a list of strings back together, with some text between them. Note the two spaces before blue.

  9. Largest, by hand

    Python has a function, max, that finds the largest value in a list. Do not use it here: the exercise is to write what it does.

    Write largest(values), which returns the largest number in the list. It prints nothing and does not change the list.

    Think about what your function should do for an empty list, decide, and say so in a comment. The checks only give it lists with at least one number.

  10. Above average

    Write above_average(scores). It returns a new list holding the scores that are greater than the mean of all of them, in their original order. The mean is the total divided by how many there are.

    The function prints nothing and does not change scores. For an empty list it returns an empty list.

    For example, the mean of 70, 85, 60 and 92 is 76.75, so the result holds 85 and 92.

  11. Playlist

    Write three functions that each change the playlist they are given and return nothing.

    • add_song(playlist, song) adds the song at the end.
    • remove_song(playlist, song) takes the song out. If it is not in the playlist, nothing changes and there is no error.
    • move_to_top(playlist, song) moves the song to the front. If it is not in the playlist, nothing changes.

    The lines below your functions then use them, and print ['Rain', 'Blue', 'Dawn'].

  12. Longest streak

    A step counter records the steps taken each day. Write longest_streak(steps, goal), which returns the length of the longest run of days in a row on which the count reached the goal. Reaching it exactly counts.

    For [9000, 12000, 10000, 3000, 11000] with a goal of 10000 the answer is 2: days two and three.

    You will need two numbers as you go: the length of the run you are in now, and the best run seen so far.

  13. The loop that skips

    This program is meant to print the list with every negative number taken out: for the list given, [4, 7, 6]. Run it. It misses some.

    Before you fix it, say to yourself which negative number is skipped first, and why. Then fix the program by building a new list named kept, leaving numbers unchanged, and print kept.

  14. Word lengths

    Write word_lengths(sentence), which returns a list holding the length of each word of the sentence, in order. For the quick brown fox it returns a list holding 3, 5, 5 and 3.

    Then draw a chart of sentence, using your function. For word number i, counting from 0:

    • a "coral" bar 70 wide at x = 40 + 90 × i, 20 tall for every letter, with its bottom edge at y = 300;
    • the word itself written at x = 40 + 90 × i, y = 330.
  15. Quiz report

    A teacher has marked a quiz out of 100. The names are in one list and the scores in another, in the same order. The teacher wants one page that shows how the class did.

    A chart with one bar for each student, as tall as the score, and the student's name under the bar. A line across the chart at the class average. The bar of the top scorer stands out from the rest. Then, in writing: the name of everyone who scored below the average, and after that every student with a letter grade.

    There are no steps this time, and no starter beyond the two lists. Plan first: which functions does this need, and what does each take and give back? So that your report can be checked, keep to these:

    • A bar is a rectangle 50 wide with its bottom edge on y = 340, 3 tall for every point of the score. The bars stand in the order of the lists, left to right.
    • Each student's name is written with text, in the same left-to-right order as the bars.
    • The average line is a rectangle 2 tall whose top edge is at y = 340 − 3 × the average, at least as wide as the row of bars.
    • The top scorer's bar is "gold". Every other bar is one other colour, which you choose. If two students share the top score, the first of them in the list is the top scorer.
    • grade(score) returns "A" for 90 or more, "B" for 80 or more, "C" for 70 or more, "D" for 60 or more, and "F" below that.
    • The program prints the name of each student below the average, one name to a line, in the order of the list. After those it prints one line for every student: the name, a space, and the grade.

    Everything else is yours to decide: the functions, the gaps between bars, the colours, where the names go. The lists always hold at least one student, and the two are always the same length.