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:
- The dictionary has two entries.
person["name"]finds the key"name"and gives its value,"Ada". person["city"] = "London"adds a new key.person["age"] = 37finds the existing key"age"and replaces its value.get("email", "not given")looks for"email". It is missing, so the method returns the default text."age" in personchecks the keys, not the values, and givesTrue.- The loop unpacks each
(key, value)pair fromitems()and prints it. The entries appear in insertion order. delremoves"city", leaving two entries.
The output is:
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.
Common mistakes¶
-
Reading a key that is not there. The code
person = {"name": "Ada"}followed byprint(person["email"])gives:Use
person.get("email")when a key might be missing, or check withif "email" in person:first. -
Using a list as a key. The code
lookup = {}followed bylookup[[1, 2]] = "x"gives:Use a tuple, such as
(1, 2), as the key instead. -
Expecting a list index to work on a dictionary. The code
person = {"name": "Ada"}followed byprint(person[0])gives:The key
0does not exist. A dictionary has no positions to read from. -
Writing an empty set as
{}. The codeempty = {}makes a dictionary, not a set. Check withprint(type(empty)), which shows<class 'dict'>. Useset()for an empty set. -
Confusing
inwith values. The check"Ada" in personlooks at the keys, so for the dictionary above it givesFalse. To test the values, write"Ada" in person.values().
Practice¶
- Create
capitals = {"France": "Paris"}. Add"Japan": "Tokyo"and assert thatlen(capitals)is 2. - Create
stock = {"pens": 4}. Assert thatstock.get("pencils", 0)is 0, and thatstock["pens"]is 4. - Create
ages = {"Ada": 36, "Ben": 41}. Use aforloop overages.items()to build a new integertotalby adding every age. Assert thattotalis 77. - Create
letters = ["a", "b", "a"]and an empty dictionarycounts. Count each letter withcounts[letter] = counts.get(letter, 0) + 1. Assert thatcountsequals{"a": 2, "b": 1}. - Stretch: create
inventory = {"apple": 3, "pear": 0, "fig": 5}. Usedelto remove every key whose value is 0. Assert that the result equals{"apple": 3, "fig": 5}.
Solution
-
python capitals = {"France": "Paris"} capitals["Japan"] = "Tokyo" assert len(capitals) == 2 -
python stock = {"pens": 4} assert stock.get("pencils", 0) == 0 assert stock["pens"] == 4 -
python ages = {"Ada": 36, "Ben": 41} total = 0 for name, age in ages.items(): total = total + age assert total == 77 -
python letters = ["a", "b", "a"] counts = {} for letter in letters: counts[letter] = counts.get(letter, 0) + 1 assert counts == {"a": 2, "b": 1} -
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 withd[key] = value. - Use
get(key, default)to read a key that might be missing, andinto check whether a key exists. - Since Python 3.7, entries keep their insertion order. Loop over
items()to get keys and values together.