Skip to content

Dictionaries

~20 min ยท prerequisite: Lists

What you will be able to do

  • Create a dictionary that maps keys to values, and read a value by its key.
  • Add, change, and remove entries, and check whether a key exists with in.
  • Loop over the keys, the values, or both, and read a value safely with get.

The idea

A dictionary, written dict, stores pairs. Each pair has a key, which you use to look up the pair, and a value, which is the data you want. A dictionary is written with curly braces and colons, such as {"name": "Ada", "age": 36}. Here the keys are the strings "name" and "age". The values are "Ada" and 36.

You read a value by putting its key in square brackets, so person["name"] gives "Ada". Lists find items by position, but dictionaries find items by key. The keys are not positions, so person[0] does not mean "the first entry". It looks for a key named 0, and fails if there is none.

To add an entry, or to change one that exists, assign to a key: person["city"] = "London" adds a new key, and person["age"] = 37 replaces the old value. The statement del person["age"] removes an entry. The method pop("age") removes an entry and returns its value.

Keys must be hashable, which means Python can compute a fixed number for them. Strings, numbers, and tuples of those are hashable. Lists and dictionaries are not, so they cannot be keys. Values can be any type, including lists.

Since Python 3.7, a dictionary keeps its entries in the order they were inserted. You can rely on that order when you loop. The method get(key, default) returns the value for a key, or the default if the key is missing, and it does not raise an error. The methods keys(), values(), and items() return views you loop over. The view from items() gives a key and a value on each step, which you can unpack with for key, value in ....

Dictionaries are the standard way to count things, look up data by name, and store a record with labeled fields.

Worked example

person = {"name": "Ada", "age": 36}
print(person["name"])

person["city"] = "London"
person["age"] = 37
print(person)

print(person.get("email", "not given"))
print("age" in person)

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

del person["city"]
print(len(person))

Line by line, this is what Python does:

  1. The dictionary has two entries. person["name"] finds the key "name" and gives its value, "Ada".
  2. person["city"] = "London" adds a new key. person["age"] = 37 finds the existing key "age" and replaces its value.
  3. get("email", "not given") looks for "email". It is missing, so the method returns the default text.
  4. "age" in person checks the keys, not the values, and gives True.
  5. The loop unpacks each (key, value) pair from items() and prints it. The entries appear in insertion order.
  6. del removes "city", leaving two entries.

The output is:

Ada
{'name': 'Ada', 'age': 37, 'city': 'London'}
not given
True
name = Ada
age = 37
city = London
2

Try it

The first block checks reading, adding, and changing entries. The second block checks get, in, and del. The third block counts words with a dictionary, which is a common use.

scores = {"Ada": 90, "Ben": 75}
assert scores["Ada"] == 90
scores["Cy"] = 60
assert scores["Cy"] == 60
scores["Ben"] = 80
assert scores["Ben"] == 80
assert len(scores) == 3
prices = {"apple": 3, "pear": 2}
assert prices.get("kiwi", 0) == 0
assert prices.get("apple", 0) == 3
assert "pear" in prices
assert 3 not in prices
del prices["pear"]
assert "pear" not in prices
assert list(prices.keys()) == ["apple"]
words = ["red", "blue", "red", "red"]
counts = {}
for word in words:
    counts[word] = counts.get(word, 0) + 1
assert counts == {"red": 3, "blue": 1}
assert counts["red"] == 3

Common mistakes

  1. Reading a key that is not there. The code person = {"name": "Ada"} followed by print(person["email"]) gives:

    KeyError: 'email'
    

    Use person.get("email") when a key might be missing, or check with if "email" in person: first.

  2. Using a list as a key. The code lookup = {} followed by lookup[[1, 2]] = "x" gives:

    TypeError: unhashable type: 'list'
    

    Use a tuple, such as (1, 2), as the key instead.

  3. Expecting a list index to work on a dictionary. The code person = {"name": "Ada"} followed by print(person[0]) gives:

    KeyError: 0
    

    The key 0 does not exist. A dictionary has no positions to read from.

  4. Writing an empty set as {}. The code empty = {} makes a dictionary, not a set. Check with print(type(empty)), which shows <class 'dict'>. Use set() for an empty set.

  5. Confusing in with values. The check "Ada" in person looks at the keys, so for the dictionary above it gives False. To test the values, write "Ada" in person.values().

Practice

  1. Create capitals = {"France": "Paris"}. Add "Japan": "Tokyo" and assert that len(capitals) is 2.
  2. Create stock = {"pens": 4}. Assert that stock.get("pencils", 0) is 0, and that stock["pens"] is 4.
  3. Create ages = {"Ada": 36, "Ben": 41}. Use a for loop over ages.items() to build a new integer total by adding every age. Assert that total is 77.
  4. Create letters = ["a", "b", "a"] and an empty dictionary counts. Count each letter with counts[letter] = counts.get(letter, 0) + 1. Assert that counts equals {"a": 2, "b": 1}.
  5. Stretch: create inventory = {"apple": 3, "pear": 0, "fig": 5}. Use del to remove every key whose value is 0. Assert that the result equals {"apple": 3, "fig": 5}.
Solution
  1. python capitals = {"France": "Paris"} capitals["Japan"] = "Tokyo" assert len(capitals) == 2

  2. python stock = {"pens": 4} assert stock.get("pencils", 0) == 0 assert stock["pens"] == 4

  3. python ages = {"Ada": 36, "Ben": 41} total = 0 for name, age in ages.items(): total = total + age assert total == 77

  4. python letters = ["a", "b", "a"] counts = {} for letter in letters: counts[letter] = counts.get(letter, 0) + 1 assert counts == {"a": 2, "b": 1}

  5. python inventory = {"apple": 3, "pear": 0, "fig": 5} for name in list(inventory.keys()): if inventory[name] == 0: del inventory[name] assert inventory == {"apple": 3, "fig": 5}

The loop uses list(inventory.keys()) so it does not change the dictionary while it loops over it.

Recap

  • A dictionary maps unique, hashable keys to values. Read with d[key], and write with d[key] = value.
  • Use get(key, default) to read a key that might be missing, and in to check whether a key exists.
  • Since Python 3.7, entries keep their insertion order. Loop over items() to get keys and values together.

Sources