Organizing Data with Dictionaries

Introduction

Welcome to Organizing Data with Dictionaries in Python! This is the first unit of the course, so we are starting fresh with a brand-new kind of collection.

So far in this learning path, we have worked with strings and lists. Both are ordered: every character or item sits at a numbered position, and we reach it with an index. That works beautifully when order is what matters, such as with a ranked leaderboard or the letters of a word. But plenty of real data is not really about order at all. Think of a user profile: a name, an age, and a city. Those pieces are not "first" or "third"; they are labeled.

That is exactly what a dictionary gives us: a collection where each value is stored under a name we choose. In this lesson, we will:

  1. Build dictionaries using the literal syntax;
  2. Read values by key with square brackets;
  3. Handle keys that might be missing without crashing;
  4. Check whether a key exists at all.

Everything we write will build toward one small, practical example: a user profile. Let us begin by seeing why labels beat positions for this kind of data.

Why Dictionaries: Labels Instead of Positions

Imagine storing a user's details in a list, as we learned to do in the previous course. It works, but notice how much we have to remember:

Python
# A list: we must remember what each position means
user_list = ["Ada", 36, "London"]
print(user_list[1])  # 36 ... but was age at index 1 or index 2?

# A dictionary: each value carries a readable label
user_dict = {"name": "Ada", "age": 36, "city": "London"}
print(user_dict["age"])  # 36, and the code says so out loud

With the list, user_list[1] is silent about its meaning; if someone inserts a middle name later, every index shifts, and our code quietly breaks. The dictionary version asks for "age" directly, so nothing depends on position.

We could also try a list of pairs, such as [["name", "Ada"], ["age", 36], ["city", "London"]]. That fixes the labels, but to find the age we would still have to walk the list until we hit the pair that starts with "age". A dictionary skips the walk: we hand it the key and it hands back the value. That direct lookup, not just the labeling, is what makes it a different tool.

This introduces the vocabulary we will use throughout the course:

  • A key is the label we look up, such as "age".
  • A value is the data stored under that label, such as 36.
  • Together, they form a key-value pair, and a dictionary is a mapping from keys to values.

The mapping can be pictured as each key pointing directly to its corresponding value:

Diagram showing the keys name, age, and city mapped to the values Ada, 36, and London

The headline idea: dictionaries are looked up by key, never by position.

Creating a Dictionary with a Literal

The most direct way to create a dictionary is with a literal: curly braces wrapping key: value pairs, separated by commas. When a dictionary has more than a couple of entries, we usually spread it across multiple lines for readability.

Python
user = {
    "name": "Ada",
    "age": 36,
    "city": "London",
}

print(user)

A few details are worth noticing in this snippet:

  • Each pair uses a colon between the key and its value, and a comma separates one pair from the next.
  • That comma after the last pair is a trailing comma. Python allows it, and it makes adding a new line later a one-line change.
  • Values can be any type; this example includes strings for "Ada" and "London" and an integer for 36.
  • Keys are often strings, but they can be any hashable value—one Python can use as a stable label—such as an integer or a tuple of hashable values. Keys must be unique; lists and dictionaries are not hashable and cannot be keys.

Printing the whole dictionary shows all pairs in the order in which we wrote them. Python guarantees this: since version 3.7, a dictionary remembers the order its pairs were added, so we can rely on it rather than treat it as luck:

text
{'name': 'Ada', 'age': 36, 'city': 'London'}

If we ever need a dictionary with no entries yet, we write {} and fill it in later.

Looking Up Values with Square Brackets

Reading a single value uses the same square brackets we used with strings and lists, but with an important twist: the brackets now hold a key instead of a numeric index.

Python
# Look up a value by its key
print("Name:", user["name"])

Python finds the pair whose key is "name" and hands back its value, so the output is:

text
Name: Ada

The key must match exactly. Dictionary keys are case-sensitive and whitespace-sensitive, so user["Name"] and user["name "] are not the same as user["name"]. When we ask for a key that the dictionary does not contain, Python raises a KeyError:

Python
print(user["email"])  # KeyError: 'email'

A KeyError is not a warning we can ignore; it is an error that stops the program right there, so any code after it never runs. That is helpful when a missing key really means something is broken, but risky when the key is simply optional.

Safer Lookups with get()

For optional data, dictionaries offer the get() method. Instead of raising an error, get() returns None when the key is absent, and we can pass a second argument to choose our own fallback value.

Python
# get() returns None (or a default) instead of raising for missing keys
print("Email:", user.get("email"))
print("Email or default:", user.get("email", "not provided"))

The first call finds no "email" key and quietly returns None, which prints as the word None. The second call finds no "email" key either, so it returns our fallback string instead:

text
Email: None
Email or default: not provided

Here is how we choose between the two lookup styles:

SituationUseMissing key result
The key must be thereuser["name"]Raises KeyError
The key is optionaluser.get("email")Returns None
We want a fallbackuser.get("email", "not provided")Returns "not provided"

When the key is present, get() simply returns the stored value, exactly like brackets. And importantly, get() never modifies the dictionary: a fallback is returned to us, not saved as a new entry.

Checking Whether a Key Exists with in

Sometimes we do not want a value at all; we just want to know whether a key is there. The in operator, which we used for membership testing on lists and strings, works here, too, and returns a Boolean.

Python
# `in` checks whether a key exists
print("Has age:", "age" in user)
print("Has phone:", "phone" in user)

Our user dictionary has an "age" pair but no "phone" pair, which gives us:

text
Has age: True
Has phone: False

The critical detail: for dictionaries, in inspects keys only, not values. So "Ada" in user would be False, even though "Ada" is stored in the dictionary as a value. The not in form works the same way, reporting True when a key is absent. This makes in a natural guard before bracket access:

Python
if "city" in user:
    print(user["city"])  # safe: we already confirmed the key exists

Putting It All Together

Let us assemble every piece into one complete script so we can see how creation, bracket lookup, get(), and in cooperate on a single user profile.

Python
user = {
    "name": "Ada",
    "age": 36,
    "city": "London",
}

# Look up a value by its key
print("Name:", user["name"])

# get() returns None (or a default) instead of raising for missing keys
print("Email:", user.get("email"))
print("Email or default:", user.get("email", "not provided"))

# `in` checks whether a key exists
print("Has age:", "age" in user)
print("Has phone:", "phone" in user)

Each printed line traces back to one technique: bracket access for a key we know exists, get() for an optional key with and without a default, and in for two membership checks.

text
Name: Ada
Email: None
Email or default: not provided
Has age: True
Has phone: False

Two reminders as we finish: keys must match exactly, and we reach for brackets when a key is guaranteed and get() when it is not.

Conclusion and Next Steps

Nicely done: we have covered the whole foundation of dictionaries in Python. We now know how to build a dictionary with a literal using curly braces and key: value pairs, read a value with square brackets around a key, fall back gracefully with get() (either accepting None or supplying our own default), and test for a key's presence with in and not in. Along the way, we saw why labels are safer than positions and why a KeyError demands our attention.

The practices ahead put these tools straight into your hands: you will create a user dictionary of your own, read a key that does not exist, soften that result with a sensible default, and run membership checks on two different keys. In the next unit, we will make dictionaries feel truly alive by adding, updating, and removing entries. For now, open the editor and start mapping some data of your own!

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal