A dictionary stores pairs written as key: value inside braces, separated by commas. The key names the entry and the value holds the data. Any type can be a value, and one dictionary may mix several types.
Square brackets hold the key instead of a position. There is no index, no slice and no negative counting: the key is the only way in.
| Form | Meaning | Example | Result |
|---|---|---|---|
| d[k] | the value stored under k | stock["pen"] | 4 |
| d.get(k) | the same value, None when k is absent | stock.get("cap") | None |
| d.get(k, v) | the value, or v when k is absent | stock.get("cap", 0) | 0 |
| k in d | true when k is one of the keys | "book" in stock | True |
| len(d) | how many pairs | len(stock) | 3 |
| d.keys() | every key | stock.keys() | ['pen', 'book', 'bag'] |
| d.values() | every value | stock.values() | [4, 2, 7] |
| d.items() | every pair | stock.items() | [('pen', 4), ...] |
A key that does not exist raises KeyError and stops the program. get raises nothing: it answers None, or the default you pass as a second argument. Use brackets when the key must be there, and get when it may be missing.
The dictionary below holds three keys. Pick one, then read it with brackets and with get. The fourth option in the list is a key that was never written.
A dictionary is mutable. One assignment covers two jobs: it creates the pair when the key is new, and it replaces the value when the key is already there. Each row below starts from the same dictionary on the left.
stock["bag"] = 7the key is new, so a pair is added at the endstock["pen"] = 9the key exists, so the value is replaced in placedel stock["pen"]drops the pair, raises KeyError when the key is absenttaken = stock.pop("pen")drops the pair and returns the value taken = 4stock.update({"book": 5, "bag": 7})writes several pairs at once, replacing what matches"book" in stocktrue when the key is present, false otherwise| Call | What it returns | Write it as |
|---|---|---|
| d[k] = v, del d[k], .update, .clear | None | stock.update(extra) |
| .pop | the value it removed | taken = stock.pop("pen") |
| .get, k in d, len(d) | a new value, d stays as it was | count = stock.get("cap", 0) |
A plain for loop over a dictionary hands you the keys, one per pass, never the values. When you want the values as well, ask for items and receive both names in the same header.
The second header uses two names because every item is a tuple of length two. That is the unpacking you already met with tuples, applied once per pass.
Counting is the task dictionaries were made for. The pattern starts from an empty dictionary and uses get with a default of zero, so the first sighting of a letter needs no special treatment.
| Pass | ch | counts.get(ch, 0) | counts after the line |
|---|---|---|---|
| 1 | 'a' | 0 | {'a': 1} |
| 2 | 'b' | 0 | {'a': 1, 'b': 1} |
| 3 | 'a' | 1 | {'a': 2, 'b': 1} |
A matrix is a list whose values are themselves lists. Each inner list is one row, and the values inside it are the columns of that row. Nothing new is added to the language: it is the list you already know, holding lists.
| Form | Meaning | Example | Result |
|---|---|---|---|
| grid[r] | the whole row at position r | grid[0] | [8, 3, 5] |
| grid[r][c] | one value: row r, column c | grid[2][0] | 6 |
| len(grid) | how many rows | len(grid) | 3 |
| len(grid[r]) | how many columns in that row | len(grid[1]) | 3 |
| grid[r][c] = v | replaces one value | grid[0][1] = 0 | row becomes [8, 0, 5] |
The first bracket applies to the matrix and gives a list. The second bracket applies to that list and gives a value. So grid[1][2] means: take row 1, then take position 2 of what you got. Row first, column second.
Click any cell of the matrix. The panel below shows the expression that reaches it, the value it holds, and the row that contains it.
One loop walks the rows. A second loop, written inside the first, walks the values of the row that the outer loop is holding at that moment. The inner loop runs from start to finish once per row.
Walking the values is enough for a sum. When the output has to name where each value sits, count with range on both levels instead.
A value inside a dictionary may be a list, and a value inside a list may be a dictionary. The two types nest in any combination, and each level is read with the bracket that belongs to it.
| Shape | Written as | Reach one value with | Useful for |
|---|---|---|---|
| Dictionary of lists | {"ana": [7, 9]} | marks["ana"][0] | several results under one name |
| List of dictionaries | [{"name": "Ana"}] | people[0]["name"] | a table of records |
| Dictionary of dictionaries | {"ana": {"age": 21}} | users["ana"]["age"] | records reached by name |
The loop hands you one dictionary per pass, and that dictionary is read with a key, as any other. A matrix is the same idea with lists on the inside.
A chain of brackets looks long, and it is read as a chain of small readings. Each bracket applies to the result of the one before it, so the type of that result decides what the next bracket may hold.
school is a dictionary, so the first bracket holds a key. school["ana"] gives the inner dictionary.["marks"] gives the list [7, 9, 5].[1] gives 9.The path on the left reaches the object you want, and the last part of the line acts on it. Reaching a list lets you call list methods, reaching a dictionary lets you assign a key.
| Question | list | dictionary |
|---|---|---|
| Written with | [10, 20, 30] | {"a": 10, "b": 20} |
| Reached by | a position, fixed by the order | a key, chosen by you |
| Slicing | Yes | No |
| Repeats | The same value may appear many times | Values may repeat, keys may not |
| Grows with | append, insert | assignment to a new key |
| A loop hands you | the values | the keys |
| Reach for it when | The order carries meaning and positions are enough | Each value deserves a name and lookup by name matters |
Trace each fragment before pressing Check. The answer button is there for when your trace and the verdict disagree.
d[k] and d.get(k), and say what each one does when the key is absent.del, pop and update, and predict the dictionary each one leaves behind.keys, values and items, and count occurrences with a default of zero.grid[row][column], and walk it with nested loops.