Topic 02

Walking a Dictionary

Hands-on

Once a dictionary holds data, two things come up constantly: going through all of it, and asking for a key that might not be there. Python has a clean way to do both, and a crash, the KeyError, for the moment you forget the second one.

Think of asking a hotel receptionist for a guest's room. A good receptionist says "no guest by that name" instead of fainting. A dictionary lookup with square brackets is the fainting kind; this page introduces the calm kind.

Walking the Keys

A for loop over a dictionary gives you its keys, one per round, in the order they were added. From each key you can reach its value with square brackets.

keys.py
phones = {"Anna": "555-0101", "Omar": "555-0142", "Lena": "555-0177"}
for name in phones:
    print(name, phones[name])
Output
Anna 555-0101
Omar 555-0142
Lena 555-0177

Keys and Values Together

The items method gives each entry as a pair of key and value. Put two names after for, separated by a comma, and Python hands the key to the first and the value to the second in every round. This is the usual way to write any report over a dictionary. The two-names trick has a name, unpacking, and the next topic explains how it works.

items.py
phones = {"Anna": "555-0101", "Omar": "555-0142", "Lena": "555-0177"}
for name, number in phones.items():
    print(f"{name}: {number}")
Output
Anna: 555-0101
Omar: 555-0142
Lena: 555-0177

If you only need the values, values gives just those.

KeyError

Ask for a key that is not in the dictionary with square brackets, and Python stops with a KeyError. The last line of the message is simply the missing key, in quotes. Nothing is wrong with the dictionary; that one key is not there.

Asking for a key that is not there
>>> phones = {"Anna": "555-0101", "Omar": "555-0142"}
>>> phones["Zoe"]
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    phones["Zoe"]
    ~~~~~~^^^^^^^
KeyError: 'Zoe'

The Calm Lookup: get

The get method looks a key up without crashing. If the key exists, it gives the value. If not, it gives None, or a default you choose as the second argument. get never adds the key; it only reads. When you need to know first, in answers whether a key is present.

Looking up safely
>>> phones.get("Anna")
'555-0101'
>>> phones.get("Zoe")
>>> phones.get("Zoe", "unknown")
'unknown'
>>> "Zoe" in phones
False

The second line printed nothing because the result was None, and the prompt shows nothing for None.

Asking for a key
The key is there→d[key] and d.get(key) both give its value
Missing, asked with d[key]→KeyError, the program stops
Missing, asked with d.get(key, default)→the default comes back
Common Confusions
  • "Looping over a dictionary gives its values." A plain loop gives the keys. Use values for values, or items for both.
  • "get adds the missing key." It only reads. The dictionary is exactly the same afterwards.
  • "A KeyError means the dictionary is broken." It means one key was missing. Check the spelling, or use get with a default.
Why It Matters
  • Data from outside is often incomplete. get with a sensible default is the first line of defence against it.
  • for key, value in d.items() is how nearly every report over a dictionary is written, in every Python project.

Knowledge Check

What does for name in phones: give on each round, when phones is a dictionary?

  • Each value, which here is a phone number
  • Each key, which here is a person's name
  • Each key and value together as a pair
  • The position of each entry, counting from 0

What does phones.get("Zoe", "unknown") give when Zoe is not a key?

  • A KeyError, because Zoe is missing from phones
  • The text unknown, the default that was passed
  • None, whatever second value was passed to get
  • A new entry for Zoe, stored with the value unknown

What does the error KeyError: 'Zoe' tell you?

  • The dictionary is empty, so there are no keys in it to look up yet
  • The key Zoe exists but its value is set to None
  • The name phones was never given a value anywhere
  • The key Zoe was asked for with square brackets and is not there

What do the two names in for name, number in phones.items(): receive?

  • Two separate dictionaries, split from phones
  • The first and the last entry of the dictionary
  • The key and the value of one entry, each round
  • Two copies of the key, for comparing with each other

You got correct