Dictionaries in Python

Say you're storing students' grades. The first idea is two lists, names and grades, with matching positions linking them.

Python 3.13
names = ["John", "Mary", "Kate"]
grades = [90, 75, 80]

To find Mary's grade you first have to locate her position in names, then read the same position in grades. Add a student and you must remember to append to the second list too. Let one list drift by a single element and Mary gets someone else's grade, and the program won't say a word. The link between a name and a grade lives only in your head, not in the code.

A dictionary removes the index middleman and ties the name straight to its value.

Python 3.13
grades = {"John": 90, "Mary": 75, "Kate": 80}
print(grades["Mary"])
75

A phone book works the same way: you find a person by name, not by line number.

Creating a dictionary

Most often a dictionary is written directly, in curly braces: a key: value pair, pairs separated by commas.

Python 3.13
# An empty dictionary to fill later
prices = {}

# A dictionary with data right away
person = {"name": "John", "age": 30, "city": "New York"}
print(person)
{'name': 'John', 'age': 30, 'city': 'New York'}

If the pairs already exist somewhere, for instance arriving as pairs, you can build a dictionary with the dict() function.

Python 3.13
pairs = [("name", "Anna"), ("age", 28), ("city", "Berlin")]
person = dict(pairs)
print(person)
{'name': 'Anna', 'age': 28, 'city': 'Berlin'}

Reading a value: brackets vs get

The most direct way to get a value is square brackets with the key.

Python 3.13
person = {"name": "John", "age": 30}
print(person["name"])
John

But if the key isn't in the dictionary, the brackets don't return emptiness, they stop the program with a KeyError.

Python 3.13
person = {"name": "John", "age": 30}
print(person["phone"])  # KeyError: 'phone' — there's no such key

This isn't a flaw but a safeguard: most often reaching for a missing key is a typo or broken logic, and it's better to hear about it immediately. Brackets fit when you're sure the key exists.

When a key might be absent, there's the get() method. It returns None instead of an error, and if you pass a second argument, that argument becomes the default value.

Python 3.13
person = {"name": "John", "age": 30}

print(person.get("phone"))
None
print(person.get("phone", "not provided"))
not provided

Hence a simple rule of thumb: brackets when a missing key is an error, get() when a missing key is a normal case you're ready to handle.

Adding and changing

A dictionary uses the same syntax to add a key and to change an existing one: assignment by key. If the key wasn't there, it appears; if it was, the value is overwritten.

Python 3.13
person = {"name": "John", "age": 30}

# Key "city" didn't exist — it gets added
person["city"] = "New York"
print(person)
{'name': 'John', 'age': 30, 'city': 'New York'}
# Key "age" already exists — the value is replaced
person["age"] = 31
print(person)
{'name': 'John', 'age': 31, 'city': 'New York'}

When you need several changes at once, update() is handier: it adds new keys and overwrites matching ones in a single call.

Python 3.13
person = {"name": "John", "age": 31}
person.update({"age": 32, "job": "developer"})
print(person)
{'name': 'John', 'age': 32, 'job': 'developer'}

Checking whether a key exists

To find out in advance whether a key is present, use the in operator. This is exactly how you avoid a KeyError when you do need the brackets.

Python 3.13
person = {"name": "John", "age": 30}

print("name" in person)
True
print("phone" in person)
False

Removing

You can drop a key with the del operator. But if the key isn't there, del also fails with a KeyError.

Python 3.13
person = {"name": "John", "age": 30, "job": "developer"}

del person["job"]
print(person)
{'name': 'John', 'age': 30}

The pop() method removes a key and returns its value at the same time, which helps when you still need the value being removed. With a second argument it doesn't fail on a missing key but returns the default instead.

Python 3.13
person = {"name": "John", "age": 30}

age = person.pop("age")
print(age)
30
# Key "phone" doesn't exist, but the second argument saves us from an error
phone = person.pop("phone", "not provided")
print(phone)
not provided

Iterating over a dictionary

You can walk through a dictionary with a loop. By default a for loop goes over the keys, and the value is easy to fetch by key.

Python 3.13
grades = {"John": 90, "Mary": 75, "Kate": 80}

for name in grades:
    print(name, ":", grades[name])
John : 90
Mary : 75
Kate : 80

If you need both the key and the value inside the loop, the items() method hands them over as a pair at once, with no lookup by key.

Python 3.13
grades = {"John": 90, "Mary": 75, "Kate": 80}

for name, grade in grades.items():
    print(name, ":", grade)
John : 90
Mary : 75
Kate : 80

There are matching methods too: keys() gives only the keys, values() only the values. They're useful when the other half of the pair isn't needed in the loop.

Python 3.13
grades = {"John": 90, "Mary": 75, "Kate": 80}

total = 0
for grade in grades.values():
    total = total + grade
print("Total points:", total)
Total points: 245

A common task: counting

A dictionary is a great fit for counting something: the key is the object, the value is the counter. Let's count how many times each word appears.

The straightforward version looks like this: for each word we check whether we've seen it before, and either bump the counter or start a new one.

Python 3.13
text = "one two one two three"
words = text.split()

counts = {}
for word in words:
    if word in counts:
        counts[word] = counts[word] + 1
    else:
        counts[word] = 1
print(counts)
{'one': 2, 'two': 2, 'three': 1}

This is exactly where get() with a default helps: "take the current counter, and if the word wasn't there yet, treat it as zero." The if/else collapses into one line.

Python 3.13
text = "one two one two three"
words = text.split()

counts = {}
for word in words:
    counts[word] = counts.get(word, 0) + 1
print(counts)
{'one': 2, 'two': 2, 'three': 1}

What can be a key

Keys live by two rules, and both follow from how a dictionary is built internally.

  • Keys are unique. You can't write two identical keys: the second assignment simply overwrites the first. That makes sense — otherwise it would be unclear which value the key "Mary" should return.
  • A key must be immutable. Strings, numbers, and tuples work. A list can't be a key: Python finds a value by the key through its immutable contents, and a list could be changed after it became a key, which would "lose" the value.
Python 3.13
# A list as a key — an error
broken = {[1, 2]: "value"}  # TypeError: unhashable type: 'list'

Values, on the other hand, can be anything: numbers, strings, lists, even other dictionaries.

Check your understanding

What does print(person["phone"]) output if the dictionary person has no "phone" key?