Lists and dictionaries
Keeping many values under one name: a list when order matters, a dictionary when you look things up by name.
A list keeps things in order
So far every name has held one value. A list holds a row of them, in order, under one name: ["flour", "water", "salt"]. Square brackets build it; commas separate the items.
Each item has a position, called an index, and the first is at 0 — the number is a distance from the start, not a count. ingredients[0] is flour, ingredients[1] is water. append adds a new item to the end, and len says how many there are.
Building a list
ingredients = ["flour", "water", "salt"]
ingredients.append("olives")
print(ingredients[0])
print(len(ingredients))Walking a list
Lists and loops are partners. for item in ingredients: hands the body one item per turn, in order, from first to last — no index arithmetic, no counting.
That is the form to reach for first. The index is there when you genuinely need a position, but most work with a list is simply "for each thing in it, do this".
Dictionaries look things up by name
A dictionary also holds many values, but you reach them by a key instead of a position: {"flour": 2, "olives": 5}. Square brackets look the value up by its key, prices["olives"], and assigning to a key adds it or replaces what was there.
Use a list when the order is the point — the steps of a recipe. Use a dictionary when one value describes another — a name and its phone number, a word and its meaning. The rule of thumb: if you would ask for it by name, keep it in a dictionary.
A small price list
prices = {"flour": 2, "olives": 5}
prices["salt"] = 1
print(prices["olives"])
print(prices)A shopping list that grows
Add olives and rosemary to the list, print how many ingredients there are with a count line, and keep the loop printing each one.
Slicing takes a run of items
Square brackets also take a slice: ingredients[1:3] gives a new list of the items at positions 1 and 2, stopping before 3 just as range does. Leave out the start and it begins at the front; leave out the end and it runs to the last item. ingredients[-1] is the final item, and ingredients[:] is a copy of the whole list.
A slice never raises IndexError for an end that is too large — it simply stops at the end — which makes it a forgiving way to take “the first three”. The index form is strict, and that difference is worth knowing before a loop depends on it.
A key must be findable
Dictionary keys are compared by value, and only types that never change can be keys: text, numbers, tuples. A list cannot be a key because it can change, and a key that changes would no longer be in the place the dictionary put it.
Looking up a key is fast because the dictionary computes where it belongs rather than searching from the start. That is also why the order of a dictionary is insertion order rather than sorted order: the storage is arranged for lookup, not for reading.
The first item is at 0, so the last item in a list of n things is at n − 1. When an index is off by one, that is the arithmetic to check first.
Names can point at the same list
A list is mutable: append and index assignment change the list itself, and every name that points at it sees the change. b = a does not copy the list; it gives the same list a second name. Change b and a changes too.
Copy when you mean copy: b = a[:] or b = list(a) makes a new list with the same items. A dictionary follows the same rule — other = prices shares it, and dict(prices) makes a shallow copy. Shallow means nested lists are still shared, which matters once values contain other collections.
Walking a dictionary
A dictionary is also iterable, but a plain for key in prices: hands you the keys. To get both, use prices.items(), which gives a pair per turn: for item, price in prices.items():.
The order is the order the keys were inserted, not sorted. If the reader needs alphabetical output, sort the keys first; do not assume the dictionary will do it.
Three mistakes: reading ingredients[3] in a three-item list raises IndexError, because the last index is 2; looking up a missing key with prices["yeast"] raises KeyError, while prices.get("yeast") returns None; and b = a copies the name, not the list.
Try these next
- Make a copy of the shopping list, append to the copy, and print both to prove they differ.
- Look up a missing price with
[]and with.get, and compare the two outcomes. - Print the last item using both
[-1]andlen(items) - 1.
A lookup with a missing key
The two loops are ready. Add the total of the prices that exist, then give yeast a real price and check that both the lookup and the total change.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
Which item is ingredients[0]?
