Chapters
Python114 chapters

CollectionsChapter 37 of 114

Dictionaries

Look values up by a key instead of a position.

Keys and values

Python
person = {"name": "Ada", "born": 1815}
print(person["name"])
print(len(person))

Output

Ada
2

A dictionary maps a key to a value. Where a list answers "what is at position 2", a dictionary answers "what is stored under name".

Reading safely

A missing key raises KeyError:

Python
person = {"name": "Ada"}
try:
    print(person["age"])
except KeyError as problem:
    print("KeyError:", problem)

Output

KeyError: 'age'

get() returns None instead, or whatever default you pass:

Python
person = {"name": "Ada"}
print(person.get("age"))
print(person.get("age", "unknown"))
print("age" in person)

Output

None
unknown
False

Use [] when a missing key is a bug, and get() when it is expected.

Adding and changing

Assigning to a key sets it, whether or not it was there:

Python
person = {"name": "Ada"}
person["born"] = 1815
person["name"] = "Ada Lovelace"
print(person)

Output

{'name': 'Ada Lovelace', 'born': 1815}

Removing

Python
person = {"name": "Ada", "born": 1815, "scratch": True}
del person["scratch"]
print(person.pop("born"))
print(person)
print(person.pop("missing", "not there"))

Output

1815
{'name': 'Ada'}
not there

Looping

Looping over a dictionary gives the keys. items() gives both, and is what you usually want:

Python
person = {"name": "Ada", "born": 1815}

for key in person:
    print(key)

for key, value in person.items():
    print(key, "=", value)

Output

name
born
name = Ada
born = 1815

keys() and values() do what they say:

Python
person = {"name": "Ada", "born": 1815}
print(list(person.keys()))
print(list(person.values()))

Output

['name', 'born']
['Ada', 1815]

Order is insertion order

Since Python 3.7 a dictionary keeps keys in the order they were added. That is a language guarantee now, not an accident:

Python
scores = {}
scores["c"] = 3
scores["a"] = 1
print(list(scores))

Output

['c', 'a']

Keys must be hashable

Strings, numbers and tuples work. Lists do not:

Python
try:
    {[1]: "nope"}
except TypeError:
    print("a list cannot be a key")

Output

a list cannot be a key

Counting things

The pattern that comes up most often, and the tool that does it for you:

Python
from collections import Counter

words = ["a", "b", "a", "c", "a"]
print(Counter(words).most_common(2))

counts = {}
for word in words:
    counts[word] = counts.get(word, 0) + 1
print(counts)

Output

[('a', 3), ('b', 1)]
{'a': 3, 'b': 1, 'c': 1}

Merging

Python
defaults = {"colour": "black", "size": 10}
custom = {"size": 12}
print(defaults | custom)
print({**defaults, **custom})

Output

{'colour': 'black', 'size': 12}
{'colour': 'black', 'size': 12}

The right-hand side wins on a clash, which is exactly what you want for overriding defaults.

Building one

Python
words = ["ada", "grace"]
print({word: len(word) for word in words})
print(dict(zip(["a", "b"], [1, 2])))

Output

{'ada': 3, 'grace': 5}
{'a': 1, 'b': 2}

Test yourself

3 questions

What does person.get("age") give when there is no age key?

Show the answer

None — Use [] when a missing key is a bug, and get() when it is expected.

What order does looping over a dictionary give?

Show the answer

The order the keys were added — Insertion order has been a language guarantee since Python 3.7.

What does defaults | custom give when both have a size key?

Show the answer

The value from custom — The right-hand side wins, which is what you want for overriding defaults.

Next chapter

Nested Dictionaries

Dictionaries inside dictionaries, and how to read them without crashing.