CurriculumWeek 02 · Organizing dataDictionaries and structured data
Lesson 02.02 · ~25 min read

Dictionaries and structured data

Keys vs. values. Nested data (lists of dictionaries). Looping over a dictionary like a human.

By Kelvin AmoabaUpdated May 12, 2026Prerequisite: 02.01

What we're doing today

By the end of this session, you will store information in a new shape — not by position in a row, but by name. You will type someone's name and the computer will hand you back their phone number. You will keep a small list of country capitals and look them up the way you'd look up a word in a dictionary. You will also meet a quieter cousin of the list called a tuple. That is the whole goal.

If last session felt like a lot, take a breath. Everything we did with lists still applies. We are adding one more tool to the shelf.

Lists are good for "the third one." Dictionaries are good for "the one named X."

A list is a row of things in order. You ask for the first item, the second item, the fifth item — by counting. That works when the order is the point. Five exam scores in the order students sat down. Ten cities in the order you want to visit them. Fine.

But sometimes order is not the point. Sometimes you want to look something up by name. Think about the contacts app on your phone. When you want to call your sister, you do not scroll to "position 47." You type her name and the phone gives you her number. The name is the handle. The number is what you get back.

That is exactly what a dictionary is. A dictionary in Python is a way to store information by name instead of by position, like looking up a friend in your phone contacts by their name. You give it a name; it gives you back the thing stored under that name.

Here is what a list of facts looks like when it starts to hurt:

amara = ["Amara Mensah", 24, "Accra", "amara@example.com"]
amara[0]   # the name. I think.
amara[2]   # the city. probably.
amara[3]   # was that email or phone? I have to scroll up.

You are counting positions and hoping. Now compare:

amara = {
    "name": "Amara Mensah",
    "age": 24,
    "city": "Accra",
    "email": "amara@example.com",
}
amara["name"]    # "Amara Mensah" — obvious
amara["email"]   # "amara@example.com" — also obvious

You can read that code in a month and still know what is going on. That is the whole sell.

Making a dictionary

You make a dictionary with curly braces { }. Inside, you write pairs. Each pair has two halves separated by a colon. The thing on the left of the colon is called the key — that is the name, the label, the handle you'll use to look the value up. The thing on the right is called the value — that is what's actually stored. Together we call them a key/value pair, the same way a contact in your phone has a name (the key) and a phone number (the value).

capitals = {
    "Ghana": "Accra",
    "Nigeria": "Abuja",
    "Kenya": "Nairobi",
    "Egypt": "Cairo",
}

Each line is one key/value pair. The country is the key. The capital is the value. The commas at the end separate one pair from the next. The trailing comma after the last pair is optional but I keep it — it makes adding new lines easier.

To look something up, use square brackets with the key inside:

print(capitals["Ghana"])   # Accra
print(capitals["Kenya"])   # Nairobi

Read that out loud: "capitals of Ghana." That is what the brackets are doing.

Keys are almost always strings — text in quotes. They can also be numbers, but ninety-five percent of the time you'll use strings. Values can be anything you've already learned: text, whole numbers, decimal numbers, True or False, even other lists and dictionaries.

When a dictionary is the right tool, and when a list is

Quick rule of thumb. If you have many things of the same shape and the order matters, use a list. If you have one thing and you want to describe it with several named facts, use a dictionary. If you have many things and you want to describe each one with several named facts — and you will, all the time — use both. We'll get to that in a moment.

A grocery shopping list: list. The opening hours of one shop: dictionary ("Monday": "8am-7pm", "Tuesday": "8am-7pm", and so on). The contacts in your phone: list of dictionaries — one dictionary per person, all of them in one list.

What happens when you ask for a key that isn't there

Try this:

print(capitals["Mars"])

Python stops the program and shouts at you with a KeyError. A KeyError is Python's way of saying "you asked me for a key I have never heard of." Mars is not in the dictionary. Python is not going to guess.

Two ways to handle this. The first is to check before you ask:

if "Mars" in capitals:
    print(capitals["Mars"])
else:
    print("I don't know that one.")

That in checks whether "Mars" is a key in the dictionary. Same in you've used with lists.

The second way is to use .get(). The .get() method tries to find the key, and if it isn't there, it hands you back a default value of your choosing instead of crashing:

print(capitals.get("Mars"))                 # None
print(capitals.get("Mars", "Not on Earth")) # Not on Earth

The first line returns None, which is Python's word for "nothing here." The second line returns the string you passed as a backup. Use .get() when "missing" is a normal outcome you can deal with, not an emergency.

Adding, updating, and deleting entries

A dictionary is not frozen. Think of it as a pantry shelf with sticky labels on the jars. You can change what's inside a jar, you can add a new jar with a new label, and you can throw a jar out.

capitals["Ghana"] = "Accra"              # already there — no-op, same value
capitals["South Africa"] = "Pretoria"    # new jar, new label
capitals["Egypt"] = "Cairo (still)"      # update what's inside an existing jar
del capitals["Kenya"]                    # throw the jar out

The pattern is the same for adding and updating: dictionary[key] = value. If the key is new, Python adds it. If the key already exists, Python overwrites the old value. To remove a key entirely, use del.

Going through every entry

You'll often want to do something with every pair in a dictionary — print them all, count them, send each one somewhere. When you loop over a dictionary directly, you get the keys:

for country in capitals:
    print(country)

That prints Ghana, Nigeria, Egypt, and so on. Just the keys. If you want the value too, you can ask the dictionary for it inside the loop:

for country in capitals:
    print(country, "→", capitals[country])

That works, but Python has a tidier way: .items(). The .items() method gives you both halves at once:

for country, city in capitals.items():
    print(country, "→", city)

Read that carefully. On each trip around the loop, Python takes one key/value pair, puts the key into country, puts the value into city, and runs the body. You picked those two names — call them whatever fits.

There's also .keys() (just the keys) and .values() (just the values), but most of the time .items() is what you reach for.

A list of dictionaries — the shape of real data

Here is the pattern you will see again and again. Real information — rows in a spreadsheet, customers in a shop, items on a menu — is almost always a list of dictionaries. One dictionary per record. One list holding them all. Think of a spreadsheet: each row is one record, each column is a named field. A dictionary is one row. A list of dictionaries is the whole sheet.

prices = [
    {"item": "Bread",  "price": 12.0, "in_stock": True},
    {"item": "Eggs",   "price": 35.0, "in_stock": True},
    {"item": "Milk",   "price": 25.0, "in_stock": False},
    {"item": "Sugar",  "price": 18.5, "in_stock": True},
]
 
for p in prices:
    print(p["item"], "—", p["price"])

Read the loop slowly. p is one dictionary — one item — each time around. p["item"] is that item's name. p["price"] is its price. The list gives you all the records; the dictionary gives you the named parts of one record.

Want only the things you can actually buy today?

available = []
for p in prices:
    if p["in_stock"]:
        available.append(p["item"])
print(available)

That's a list and a dictionary working together. Get used to this shape. When we get to spreadsheets in a future session, you'll find they are the same idea dressed up.

A quick word about tuples

Sometimes you want a small group of values that travels together and never changes. For that, Python has a tuple. A tuple is a fixed list you can't change after you make it. You write one with commas, usually inside round brackets:

location = ("Accra", 5.6037, -0.1870)   # name, latitude, longitude
print(location[0])   # Accra
print(location[1])   # 5.6037

It looks a lot like a list. The difference is that once you've made it, you can't add to it, remove from it, or change any of its values. Try it and Python will refuse. That sounds annoying, but it's a feature. When you reach for a tuple, you're telling future-you "these three things belong together and the shape never changes." Latitude and longitude. A red/green/blue colour. A first name and a last name. A cloakroom ticket with a number and a date — you don't edit the ticket; if it changes, you get a new one.

You'll also see tuples come out of .items() whether you noticed or not — each pair Python hands you back is technically a (key, value) tuple. We just unpacked it into two names so it didn't feel like one.

For now, know they exist, know they're fixed, and use a list unless you have a reason to lock the shape.

Your exercise

Open a fresh Colab cell. Build a small contacts dictionary with at least three people in it, where the key is the person's name and the value is their phone number:

contacts = {
    "Ama": "024-111-2233",
    "Kofi": "020-555-7788",
    "Esi": "055-909-1212",
}

Then write code that does the following:

  1. Asks the user for a name with input("Whose number? ").
  2. Looks the name up in the dictionary using .get() so it doesn't crash if the name isn't there.
  3. Prints the number if it found one, otherwise prints "Sorry, I don't have that one."
  4. Adds one new contact to the dictionary at the end and prints the whole thing using a for loop with .items().

If you finish early, change the values from plain phone numbers to small dictionaries themselves — {"phone": "...", "city": "..."} — and update your lookup code so it prints both the phone and the city.

Common slip-ups

  • KeyError. You asked for a key the dictionary doesn't have. Check with in first, or use .get("key") which returns None instead of stopping the program.
  • Mixing up the dictionary and one entry inside it. In a list-of-dictionaries loop, the loop variable is one record, not the whole collection.
  • Writing contacts.Ama instead of contacts["Ama"]. The dot syntax works for some Python things, but not for dictionaries. Always square brackets and quotes.
  • Forgetting the colon between key and value. {"name", "Ama"} is not a dictionary — it's something else entirely. It must be {"name": "Ama"}.
  • Trying to change a tuple. If you need to edit it, you wanted a list, not a tuple.

Resources

★ recommended