A list holds many values in order, and you can change it after you make it. It is the collection you will use most.
Warm-up: from Days 1 and 2
Three quick ones, from memory first. Scroll back only after you’ve tried.
1. Predict both lines.
total = 0
for n in range(1, 5):
if n % 2 == 0:
total += n
print(total)
print("even" if total % 2 == 0 else "odd")Check your prediction
6
evenrange(1, 5) is 1, 2, 3, 4 — the 5 is excluded — and only 2 and 4 pass the
test.
2. Fix. Three of these ratings are 4 or more, but this prints 0.
ratings = [5, 3, 4, 4, 2]
good = 0
for r in ratings:
if r >= 4:
good + 1
print(good)Check your fix
ratings = [5, 3, 4, 4, 2]
good = 0
for r in ratings:
if r >= 4:
good += 1
print(good)3good + 1 works out a new number and throws it away — the same mistake as
calling strip() without keeping the result. += stores it back.
3. Write. Print the numbers from 10 down to 0 in steps of 2, on one line:
10 8 6 4 2 0.
# Your code hereCheck your answer
for n in range(10, -1, -2):
print(n, end=" ")
print()10 8 6 4 2 0The stop is excluded, so to include 0 when counting down you stop at -1.
range(10, 0, -2) would end at 2.
Making and reading a list
scores = [88, 72, 95, 61]
mixed = ["Ada", 36, True, 3.5] # types can be mixed, though rarely should be
empty = []
print(scores)
print(scores[0], scores[-1]) # first and last
print(scores[1:3]) # a slice - same rules as strings
print(len(scores))
print(95 in scores)Indexing and slicing work exactly as they did for strings on Day 1 — zero-based, negatives count from the end, slices exclude the stop.
Lists can be changed
This is the big difference from strings. A list is mutable: you can replace, add and remove items in place.
tasks = ["write", "test"]
tasks.append("ship") # add one to the end
print(tasks)
tasks.insert(0, "plan") # add at a position
print(tasks)
tasks.extend(["deploy", "rest"]) # add several
print(tasks);
tasks[1] = "WRITE" # replace by index
removed = tasks.pop() # remove and return the last
tasks.remove("test") # remove the first match by value
print(tasks, "| removed:", removed)append versus extend
append adds its argument as a single item — append([1, 2]) gives you a list
inside your list. extend adds each item of what you give it. When the result
surprises you, this is usually why.
Sorting
sort() reorders the list itself and returns nothing. sorted() leaves the
original alone and hands back a new list. Choosing the wrong one is a classic
bug.
scores = [88, 72, 95, 61]
print(sorted(scores)) # a new sorted list
print(scores) # original untouched
scores.sort()
print(scores) # now the original is sorted
scores.sort(reverse=True)
print(scores)
# key= decides what to sort by.
words = ["banana", "fig", "cherry"]
print(sorted(words, key=len))scores = scores.sort() destroys your data
sort() returns None, so assigning its result replaces your list with
nothing. If you want a sorted copy, use sorted().
Looping over lists
prices = [4.99, 12.50, 3.25, 8.00]
for price in prices:
print(f"${price:.2f}")
print("Total:", sum(prices))
# Building a new list from an old one.
with_tax = []
for price in prices:
with_tax.append(round(price * 1.2, 2)) # rounds the total price to two decimal places
print(with_tax)That last pattern — start empty, loop, append — is so common that Python has a one-line form for it. You will meet comprehensions on Day 4.
Copying, and the trap
Assigning a list does not copy it. Both names end up pointing at the same list, and a change through one is visible through the other.
original = [1, 2, 3]
alias = original # NOT a copy
alias.append(4)
print("original:", original)
print("alias: ", alias)
print("same object?", original is alias)
copy = original[:] # a real copy (or list(original), or original.copy())
copy.append(5)
print("original:", original)
print("copy: ", copy)This is not a wart — it is the same rule every language with references has, and it is what makes passing large lists to functions cheap. You simply have to know it is happening.
Nested lists
A list can hold lists, which is how you get grids and tables.
grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
print(grid[1]) # the middle row
print(grid[1][2]) # row 1, column 2
for row in grid:
for value in row:
print(f"{value:3}", end="") # takes at least 3 characters wide and do not move to the next line
print() # moves to the next lineBefore you write your own
Predict. Three lines. One of them depends on the section about copying.
cart = ["milk", "eggs"]
basket = cart
basket.append("bread")
print(len(cart))
print(cart[-1])
print(sorted(cart)[0])Check your prediction
3
bread
breadbasket = cart doesn’t copy anything, so appending to basket changed the one
list both names point at. And sorted puts "bread" first alphabetically.
Fix. This should print the prices from cheapest to dearest. It prints
None.
prices = [9.99, 2.50, 4.00]
prices = prices.sort()
print(prices)Check your fix
prices = [9.99, 2.50, 4.00]
prices.sort()
print(prices)[2.5, 4.0, 9.99]sort() sorts the list where it is and returns None — so assigning its result
replaced the list with nothing. Either call prices.sort() on its own, or write
prices = sorted(prices).
Score report
From the list of scores, print the count, the highest, the lowest, the average to one decimal place, and the three highest scores in descending order. Your labels can differ, but the numbers should be:
Count: 7
Highest: 95
Lowest: 61
Average: 81.7
Top 3: [95, 93, 88]scores = [88, 72, 95, 61, 79, 93, 84]
# Your code hereHint 1: the idea
Python has a built-in for most of this: len, max, min and sum. The
average is a sum divided by a count. The top three is two steps: put the scores
in descending order, then take the first three.
Hint 2: a first step
Start with print(len(scores), max(scores), min(scores)) to see the easy three.
For the top three, sorted(scores, reverse=True) gives a new list, highest
first — and a slice takes the front of any list.
Show one solution
scores = [88, 72, 95, 61, 79, 93, 84]
print(f"Count: {len(scores)}")
print(f"Highest: {max(scores)}")
print(f"Lowest: {min(scores)}")
print(f"Average: {sum(scores) / len(scores):.1f}")
print(f"Top 3: {sorted(scores, reverse=True)[:3]}")sorted(...)[:3] — sort a copy descending, then slice the first three. Using
sorted rather than sort leaves the original list in its original order,
which the rest of a program may depend on.
What you learned
- Lists are ordered, indexable, sliceable and mutable.
append,insert,extend,popandremovechange a list in place.sort()reorders in place and returnsNone;sorted()returns a new list.key=controls what sorting compares.- Assignment shares a list;
[:],list()or.copy()make a real copy.