Python Dictionnaries
Storing Data as Key-Value Pairs: Understanding Dictionaries in Python
We've learned about Lists and Tuples, which store items in an ordered sequence where you access items by their position number (index). But what if you don't want to look up information by position? What if you want to look up a value using a descriptive name or identifier?
Imagine you need to store information about a user: their name, age, city, and score. You could use a list like ["Alice", 30, "New York", 500]
, but then you have to remember that the name is at index 0, age is at index 1, etc. If you add a new piece of information, all the index numbers might change! This isn't easy to manage when you need to quickly find a user's score or city.
This is where Dictionaries come in. Dictionaries are Python's way of storing information as pairs, where each pair has a unique key and a value.
What is a Dictionary?
A Dictionary is a collection of items where each item is a key-value pair. Think of a real-world dictionary: you look up a word (the key) to find its definition (the value). In a Python dictionary, you use a key to quickly find the value associated with it.
Here are the main characteristics of dictionaries:
- Key-Value Pairs: Data is stored as
key: value
pairs. - Keys are Unique: Each key in a dictionary must be unique. You can't have two identical keys.
- Accessed by Key: You retrieve values using their key, not a position index.
- Changeable (Mutable): You can add new key-value pairs, change the value associated with an existing key, or remove key-value pairs after the dictionary is created.
- Ordered (Insertion Order): In modern Python (version 3.7+), dictionaries remember the order in which items were added. However, you still access items by key, not by their position number.
Dictionaries are written using curly braces {}
with key-value pairs inside. Each key is separated from its value by a colon :
, and pairs are separated by commas ,
.
# A dictionary storing user information
user_data = {
"name": "Alice",
"age": 30,
"city": "New York"
}
# A dictionary storing product prices
product_prices = {
"apple": 1.0,
"banana": 0.5,
"orange": 1.2
}
# An empty dictionary
empty_dict = {}
Dictionary keys are typically strings or numbers, but they can be any immutable object (like strings, numbers, or tuples). Mutable objects (like lists or other dictionaries) cannot be used as keys.
Creating Dictionaries
You can create dictionaries in several ways.
Creating an Empty Dictionary
my_settings = {} # Most common way
another_empty_dict = dict() # Using the dict() function
Creating a Dictionary with Initial Items
Put the key-value pairs inside curly braces {}
when you create the dictionary. Remember the key: value
syntax.
game_scores = {"Alice": 500, "Bob": 750, "Charlie": 600}
item_quantities = {"sword": 1, "potion": 5, "gem": 10}
You can also create a dictionary using the dict()
function with an iterable of key-value pairs (often a list of tuples):
# Create a dictionary from a list of tuples (key, value)
user_ages = dict([("Alice", 30), ("Bob", 25), ("Charlie", 35)])
print(user_ages) # Output: {'Alice': 30, 'Bob': 25, 'Charlie': 35}
Accessing Dictionary Items
You access the value associated with a key by putting the key inside square brackets []
after the dictionary variable's name.
user_data = {
"name": "Alice",
"age": 30,
"city": "New York"
}
# Get the value for the key "name"
user_name = user_data["name"]
print(user_name) # Output: Alice
# Get the value for the key "age"
user_age = user_data["age"]
print(user_age) # Output: 30
If you try to access a key that does not exist in the dictionary using []
, Python will give you a KeyError
.
Safely Accessing Items with .get()
A safer way to access an item is using the .get()
method. If the key exists, it returns the value. If the key does not exist, it returns None
by default, or a value you specify. This avoids the KeyError
.
user_data = {"name": "Alice", "age": 30}
city = user_data.get("city") # Key "city" does not exist
print(city) # Output: None (default return when key is not found)
country = user_data.get("country", "Unknown") # Key "country" not found, return "Unknown"
print(country) # Output: Unknown
name = user_data.get("name") # Key "name" exists
print(name) # Output: Alice
Using .get()
is generally preferred over []
when you're not sure if a key is present, as it prevents your program from crashing.
Changing (Modifying) Dictionary Items
Dictionaries are mutable, meaning you can change the value associated with an existing key after the dictionary is created. You use the key and the assignment operator (=
).
user_data = {"name": "Alice", "age": 30}
print(f"Original data: {user_data}") # Output: Original data: {'name': 'Alice', 'age': 30}
# Change the value for the key "age"
user_data["age"] = 31
print(f"Modified data: {user_data}") # Output: Modified data: {'name': 'Alice', 'age': 31}
The dictionary object itself is modified in memory.
Adding New Items
To add a new key-value pair to a dictionary, you use the same assignment syntax (dictionary_name[new_key] = new_value
). If the key does not already exist, it is added with the specified value.
user_data = {"name": "Alice", "age": 30}
print(f"Data before adding: {user_data}") # Output: Data before adding: {'name': 'Alice', 'age': 30}
# Add a new key "city" with value "New York"
user_data["city"] = "New York"
print(f"Data after adding city: {user_data}") # Output: Data after adding city: {'name': 'Alice', 'age': 30, 'city': 'New York'}
# Add another new key "score"
user_data["score"] = 500
print(f"Data after adding score: {user_data}") # Output: Data after adding score: {'name': 'Alice', 'age': 30, 'city': 'New York', 'score': 500}
If you use this syntax with a key that already exists, it will update the value for that key (which is how you change items, as shown above).
You can also add multiple items or merge another dictionary using the .update()
method.
user_data = {"name": "Alice", "age": 30}
new_info = {"city": "New York", "score": 500}
user_data.update(new_info) # Adds items from new_info to user_data
print(user_data) # Output: {'name': 'Alice', 'age': 30, 'city': 'New York', 'score': 500}
# If a key already exists in the update, its value is changed:
more_info = {"age": 31, "is_online": True}
user_data.update(more_info)
print(user_data) # Output: {'name': 'Alice', 'age': 31, 'city': 'New York', 'score': 500, 'is_online': True}
Removing Items
You can remove key-value pairs from a dictionary using the del
keyword or the .pop()
method.
Remove using del
The del
keyword removes the key-value pair specified by the key.
user_data = {"name": "Alice", "age": 30, "city": "New York"}
print(f"Data before del: {user_data}") # Output: Data before del: {'name': 'Alice', 'age': 30, 'city': 'New York'}
del user_data["city"] # Remove the pair with key "city"
print(f"Data after del city: {user_data}") # Output: Data after del city: {'name': 'Alice', 'age': 30}
# del user_data["country"] # This would cause a KeyError because the key doesn't exist
Remove using .pop()
The .pop(key)
method removes the item with the specified key and returns its value. Like .get()
, it can take a second argument as a default value to return if the key is not found, preventing a KeyError
.
user_data = {"name": "Alice", "age": 30}
print(f"Data before pop: {user_data}") # Output: Data before pop: {'name': 'Alice', 'age': 30}
age = user_data.pop("age") # Remove "age" and get its value
print(f"Data after pop age: {user_data}") # Output: {'name': 'Alice'}
print(f"Removed age was: {age}") # Output: Removed age was: 30
score = user_data.pop("score", 0) # Try to remove "score", return 0 if not found
print(f"Data after pop score (not found): {user_data}") # Output: {'name': 'Alice'}
print(f"Removed score was: {score}") # Output: 0 (returned the default)
Remove all items (.clear()
)
The .clear()
method removes all key-value pairs from the dictionary, making it empty.
my_dict = {"a": 1, "b": 2}
my_dict.clear()
print(my_dict) # Output: {}
Getting Keys, Values, and Items (Views)
Dictionaries provide special methods to get collections of their keys, values, or both. These methods return dictionary views. A view is like a window into the dictionary; it reflects changes made to the dictionary.
.keys()
: Returns a view object that displays a list of all the keys..values()
: Returns a view object that displays a list of all the values..items()
: Returns a view object that displays a list of key-value pairs as tuples.
user_data = {"name": "Alice", "age": 30, "city": "New York"}
all_keys = user_data.keys()
print(all_keys) # Output: dict_keys(['name', 'age', 'city'])
all_values = user_data.values()
print(all_values) # Output: dict_values(['Alice', 30, 'New York'])
all_items = user_data.items()
print(all_items) # Output: dict_items([('name', 'Alice'), ('age', 30), ('city', 'New York')])
# You can convert views to a list if you need a static list
list_of_keys = list(user_data.keys())
print(list_of_keys) # Output: ['name', 'age', 'city']
Note that the order in these views (and when iterating) is the order in which the items were first inserted into the dictionary (in Python 3.7+).
Checking if a Key Exists (in
Operator)
You can use the in
operator to quickly check if a specific key is present in a dictionary. It checks among the dictionary's keys by default.
user_data = {"name": "Alice", "age": 30}
print("name" in user_data) # Output: True (key "name" exists)
print("city" in user_data) # Output: False (key "city" does not exist)
print("age" not in user_data) # Output: False (key "age" exists)
If you need to check if a value exists, you need to use the .values()
view with in
: print(30 in user_data.values())
.
Getting the Number of Items (len()
)
Use the built-in len()
function to get the total number of key-value pairs in a dictionary.
my_dict = {"a": 1, "b": 2, "c": 3}
print(len(my_dict)) # Output: 3
empty_dict = {}
print(len(empty_dict)) # Output: 0
Iterating Through a Dictionary (for
Loop)
You can easily go through all the keys, values, or key-value pairs in a dictionary using a for
loop.
By default, a for
loop over a dictionary iterates through its keys.
user_data = {"name": "Alice", "age": 30, "city": "New York"}
print("Iterating over keys:")
for key in user_data: # Same as "for key in user_data.keys():"
print(key)
# Output:
# Iterating over keys:
# name
# age
# city
You can explicitly iterate over the views:
print("\nIterating over values:")
for value in user_data.values():
print(value)
# Output:
# Iterating over values:
# Alice
# 30
# New York
print("\nIterating over items (key-value pairs):")
# This is very common! We unpack the (key, value) tuple directly in the loop
for key, value in user_data.items():
print(f"{key}: {value}")
# Output:
# Iterating over items (key-value pairs):
# name: Alice
# age: 30
# city: New York
When to Use Dictionaries
Use dictionaries when:
- You need to look up information quickly using a specific key or name (like finding a user's score by their username).
- You are storing properties or attributes of a single item (like user data: name, age, city).
- You need to represent structured data where each piece of information has a label.
- You need unique identifiers (keys) for items.
Dictionaries are ideal for mapping unique keys to values, providing efficient lookup unlike lists or tuples where you search by position or have to loop to find a value.
Type Annotations for Dictionaries
For type hinting, you use the Dict
type from the typing
module. You need to specify the type expected for the keys and the type expected for the values inside square brackets []
.
Syntax: Dict[KeyType, ValueType]
from typing import Dict
# A dictionary where keys are strings and values are integers
player_scores: Dict[str, int] = {"Alice": 500, "Bob": 750}
# A dictionary where keys are strings and values can be different types
user_profile: Dict[str, any] = {"name": "Alice", "age": 30, "is_active": True}
# Using 'any' if values have mixed types
# A dictionary where keys are integers and values are lists of strings
data_groups: Dict[int, List[str]] = {1: ["a", "b"], 2: ["c"]}
This type annotation (Dict[str, int]
) helps document your code and allows type checkers to verify that you are using the correct types for keys and values when interacting with the dictionary.
Going Deeper: Dictionaries and Abstract Base Classes
Dictionaries implement standard interfaces defined by Abstract Base Classes (ABCs) in collections.abc
, specifically Mapping
and MutableMapping
.
-
Mapping
: This ABC defines the basic requirements for any object that acts like a read-only dictionary. It's a blueprint for collections where you can look up values by key. Types likedict
implementMapping
. It requires support for things like:- Accessing by key (
obj[key]
). - Checking if a key exists (
key in obj
). - Getting length (
len(obj)
). - Iterating over keys (
for key in obj:
). - Getting views (
.keys()
,.values()
,.items()
). - Using
.get()
method.
- Accessing by key (
-
MutableMapping
: This ABC is for mappings that can be changed after creation (they are mutable). AMutableMapping
supports everything aMapping
does, plus methods for changing the collection in place. TheMutableMapping
ABC adds requirements for things like:- Assigning to a key (
obj[key] = value
). - Deleting items (
del obj[key]
,.pop()
). - Removing all items (
.clear()
). - Updating with other items (
.update()
).
- Assigning to a key (
A Python dict
is both a Mapping
and a MutableMapping
. This means it fulfills the contracts defined by both blueprints, providing the full set of dictionary behaviors.
You can check this using isinstance()
:
import collections.abc
my_dict = {"a": 1, "b": 2}
print(isinstance(my_dict, collections.abc.Mapping)) # Output: True (A dictionary is a mapping)
print(isinstance(my_dict, collections.abc.MutableMapping)) # Output: True (A dictionary is a mutable mapping)
Understanding these ABCs helps you see how dictionaries fit into Python's type system and understand the common behaviors shared by objects that store data with keys.
Conclusion
Dictionaries are essential for storing and managing data as key-value pairs in Python. They provide a highly efficient way to look up information using descriptive keys rather than numerical indices.
Key things you learned about dictionaries:
- They store data as key: value pairs, where keys are unique and immutable.
- They are mutable (changeable).
- You create them using curly braces
{}
. - You access values using their keys (
[]
or.get()
). - You can change, add, or remove items using keys with assignment (
=
),del
,.pop()
, and.update()
. - You can get views of keys, values, and items using
.keys()
,.values()
, and.items()
. - You check for a key's existence using the
in
operator. - You get the number of pairs using
len()
. - You can easily go through keys, values, or items using a
for
loop. - You can add generic type hints (
Dict[KeyType, ValueType]
). - Dictionaries implement the
Mapping
andMutableMapping
contracts (ABCs).
Dictionaries are incredibly useful for representing structured data and performing quick lookups. Practice using them to organize data that doesn't naturally fit into a simple ordered sequence.