Python course Β· Module 2: Data Structures
Dictionaries - Cataloging Discoveries
In this lesson17
Welcome back! Darwin here with another important lesson.
In the previous lesson you learned about lists - ordered collections like expedition trails. But sometimes you need something more - a way to catalog your discoveries with additional information. In the jungle every species has its data card: habitat, size, whether it's dangerous. In Python we use dictionaries for this.
What Are Dictionaries?
A dictionary is a collection of key: value pairs. Imagine a catalog of discoveries where each species (key) has its information card (value).
1# Species catalog - key is the name, value is the details
2species_info = {
3 "Python regius": "Royal python, 1-2m, harmless",
4 "Panthera leo": "Lion, 2-3m, very dangerous",
5 "Loxodonta africana": "African elephant, 3-4m, calm"
6}
7
8# More complex catalog
9detailed_catalog = {
10 "Python regius": {
11 "common_name": "Royal Python",
12 "length_m": 1.5,
13 "habitat": "jungle",
14 "dangerous": False
15 },
16 "Panthera leo": {
17 "common_name": "Lion",
18 "length_m": 2.5,
19 "habitat": "savanna",
20 "dangerous": True
21 }
22}Key characteristics of dictionaries:
- Key-value pairs - each key leads to a value
- Keep insertion order (since Python 3.7), but have no indices - you get a value by its key
- Keys must be unique and immutable (string, int, tuple)
- Values can be anything - even other dictionaries!
- Mutable - they can be modified
Creating Dictionaries
1# Empty dictionary - clean catalog
2empty_catalog = {}
3empty_dict = dict()
4
5# Dictionary with data
6explorer_data = {
7 "name": "Darwin",
8 "age": 35,
9 "profession": "Researcher",
10 "discoveries": 47
11}
12
13# Different key types (but strings are most common)
14mixed_keys = {
15 "name": "Python",
16 42: "Answer",
17 (10, 20): "Coordinates"
18}
19
20# Nested dictionaries
21expedition = {
22 "location": "Amazonia",
23 "team": {
24 "leader": "Darwin",
25 "count": 5
26 },
27 "equipment": ["Binoculars", "Map", "GPS"]
28}
29
30# dict() constructor
31from_pairs = dict([("A", 1), ("B", 2), ("C", 3)])
32with_kwargs = dict(name="Darwin", age=35, job="Explorer")Accessing Values
1species = {
2 "Python regius": "Royal Python",
3 "Panthera leo": "Lion",
4 "Loxodonta africana": "Elephant"
5}
6
7# Access by key (square brackets)
8python_name = species["Python regius"] # "Royal Python"
9lion_name = species["Panthera leo"] # "Lion"
10
11# KeyError if key doesn't exist!
12# wrong = species["Tyrannosaurus"] # KeyError!
13
14# Safe access - get()
15python_name = species.get("Python regius") # "Royal Python"
16trex = species.get("Tyrannosaurus") # None
17trex = species.get("Tyrannosaurus", "Not found") # "Not found"
18
19print(f"Python: {python_name}")get() vs []:
dict[key]- raises KeyError if key is missingdict.get(key)- returns None if key is missingdict.get(key, default)- returns default if key is missing
Adding and Modifying
1catalog = {
2 "Python regius": {"length": 1.5, "habitat": "jungle"}
3}
4
5# Adding a new entry
6catalog["Panthera leo"] = {"length": 2.5, "habitat": "savanna"}
7
8# Modifying an existing one
9catalog["Python regius"]["length"] = 1.8
10
11# Adding via update() - dictionary or key-value pairs
12catalog.update({"Loxodonta africana": {"length": 4.0, "habitat": "savanna"}})
13catalog.update(discovered_by="Darwin", year=2024)
14
15print(catalog)Removing Elements
1species = {
2 "Python": "Python",
3 "Leo": "Lion",
4 "Elephas": "Elephant",
5 "Giraffa": "Giraffe"
6}
7
8# del - remove by key
9del species["Giraffa"]
10
11# pop() - remove and return value
12leo_value = species.pop("Leo") # "Lion"
13print(leo_value)
14
15# pop() with default (if key doesn't exist)
16dino = species.pop("T-Rex", "Not found") # "Not found"
17
18# popitem() - remove and return the LAST pair (Python 3.7+)
19last_item = species.popitem() # ("Elephas", "Elephant")
20
21# clear() - clear the entire dictionary
22species.clear()
23print(species) # {}Checking Key Existence
1catalog = {
2 "Python regius": "Python",
3 "Panthera leo": "Lion"
4}
5
6# in - check if key exists
7if "Python regius" in catalog:
8 print("Python is in the catalog!")
9
10if "T-Rex" not in catalog:
11 print("T-Rex is not in the catalog")
12
13# Note: 'in' checks KEYS, not values!
14print("Python" in catalog) # False (that's a value, not a key!)Iterating Through a Dictionary
1species = {
2 "Python regius": "Royal Python",
3 "Panthera leo": "Lion",
4 "Loxodonta africana": "African Elephant"
5}
6
7# Iterating through keys (default)
8for species_name in species:
9 print(species_name)
10
11# Explicitly through keys - keys()
12for key in species.keys():
13 print(key)
14
15# Iterating through values - values()
16for common_name in species.values():
17 print(common_name)
18
19# Iterating through key-value pairs - items() (most common!)
20for species_name, common_name in species.items():
21 print(f"{species_name}: {common_name}")
22
23# Enumerate for numbering
24for i, (key, value) in enumerate(species.items(), start=1):
25 print(f"{i}. {key} -> {value}")Dictionary Methods
keys(), values(), items()
1catalog = {
2 "Python": {"habitat": "jungle", "size": 1.5},
3 "Leo": {"habitat": "savanna", "size": 2.5}
4}
5
6# All keys
7all_keys = catalog.keys() # dict_keys(['Python', 'Leo'])
8keys_list = list(catalog.keys()) # List: ['Python', 'Leo']
9
10# All values
11all_values = catalog.values() # dict_values([{...}, {...}])
12
13# All pairs
14all_items = catalog.items() # dict_items([('Python', {...}), ('Leo', {...})])
15
16# Conversion to lists
17keys = list(catalog.keys())
18values = list(catalog.values())
19items = list(catalog.items())get() - safe access
1species = {"Python": "Python", "Leo": "Lion"}
2
3# get(key) - None if missing
4result = species.get("Python") # "Python"
5result = species.get("T-Rex") # None
6
7# get(key, default) - custom default
8result = species.get("T-Rex", "Not found!") # "Not found!"setdefault() - return value OR set a default
1catalog = {"Python": {"count": 5}}
2
3# If key exists - return value
4python_data = catalog.setdefault("Python", {"count": 0})
5print(python_data) # {'count': 5}
6
7# If key does NOT exist - add with default
8leo_data = catalog.setdefault("Leo", {"count": 0})
9print(leo_data) # {'count': 0}
10print(catalog) # {'Python': {...}, 'Leo': {'count': 0}}update() - update/merge dictionaries
1catalog1 = {"Python": "Python", "Leo": "Lion"}
2catalog2 = {"Elephas": "Elephant", "Giraffa": "Giraffe"}
3new_data = {"Python": "Royal Python"} # Will overwrite
4
5# Update with dictionary
6catalog1.update(catalog2)
7print(catalog1) # {'Python': 'Python', 'Leo': 'Lion', 'Elephas': 'Elephant', 'Giraffa': 'Giraffe'}
8
9# Update with key=value pairs
10catalog1.update(discovered_by="Darwin", year=2024)copy() - copying a dictionary
1# WARNING - this does NOT copy!
2original = {"A": 1, "B": 2}
3reference = original # Same reference!
4reference["A"] = 999
5print(original) # {'A': 999, 'B': 2} - changed!
6
7# Proper copying
8original = {"A": 1, "B": 2}
9copy1 = original.copy() # Shallow copy
10copy2 = dict(original) # Alternative
11
12copy1["A"] = 999
13print(original) # {'A': 1, 'B': 2} - unchanged!
14
15# Deep copy (for nested dictionaries)
16import copy
17nested = {"team": {"leader": "Darwin", "size": 5}}
18deep = copy.deepcopy(nested)
19deep["team"]["leader"] = "Alex"
20print(nested) # {'team': {'leader': 'Darwin', 'size': 5}} - unchanged!Dictionary Comprehensions
Similar to list comprehensions, you can create dictionaries in a single line!
1# Traditional way
2squares = {}
3for x in range(1, 6):
4 squares[x] = x ** 2
5# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
6
7# Dict comprehension!
8squares = {x: x ** 2 for x in range(1, 6)}
9# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
10
11# With condition
12even_squares = {x: x ** 2 for x in range(1, 11) if x % 2 == 0}
13# {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}
14
15# Swapping keys and values
16species = {"Python": "Python", "Leo": "Lion"}
17reversed_dict = {value: key for key, value in species.items()}
18# {"Python": "Python", "Lion": "Leo"}
19
20# From two lists
21names = ["Python", "Leo", "Elephas"]
22common_names = ["Python", "Lion", "Elephant"]
23catalog = {name: common for name, common in zip(names, common_names)}Nested Dictionaries
Dictionaries can contain other dictionaries - perfect for complex data!
1# Expedition catalog with details for each species
2species_database = {
3 "Python regius": {
4 "common_name": "Royal Python",
5 "characteristics": {
6 "length_m": 1.5,
7 "weight_kg": 2.5,
8 "habitat": "jungle"
9 },
10 "status": "discovered",
11 "discoverer": "Darwin",
12 "date": "2024-01-15"
13 },
14 "Panthera leo": {
15 "common_name": "Lion",
16 "characteristics": {
17 "length_m": 2.5,
18 "weight_kg": 190,
19 "habitat": "savanna"
20 },
21 "status": "observed",
22 "discoverer": "Team B"
23 }
24}
25
26# Accessing nested values
27python_length = species_database["Python regius"]["characteristics"]["length_m"]
28print(f"Python length: {python_length}m")
29
30# Safe access to deeply nested values
31leo_weight = species_database.get("Panthera leo", {}).get("characteristics", {}).get("weight_kg", "No data")
32print(f"Lion weight: {leo_weight}kg")Operations on Dictionaries
1# Length (number of key-value pairs)
2species = {"Python": "Python", "Leo": "Lion", "Elephas": "Elephant"}
3count = len(species) # 3
4
5# Merging dictionaries (Python 3.9+)
6dict1 = {"A": 1, "B": 2}
7dict2 = {"C": 3, "D": 4}
8merged = dict1 | dict2 # {'A': 1, 'B': 2, 'C': 3, 'D': 4}
9
10# Merging with overwriting (Python 3.9+)
11dict1 = {"A": 1, "B": 2}
12dict2 = {"B": 999, "C": 3}
13merged = dict1 | dict2 # {'A': 1, 'B': 999, 'C': 3} - B overwritten!
14
15# |= operator (modifies the first dictionary)
16dict1 |= dict2 # dict1 now contains merged data
17
18# Min/Max of keys
19species = {"Python": 5, "Leo": 12, "Elephas": 3}
20max_key = max(species) # "Python" (alphabetically)
21max_value = max(species.values()) # 12
22max_by_value = max(species, key=species.get) # "Leo" (highest value)Sorting Dictionaries
1species_count = {
2 "Python": 5,
3 "Leo": 12,
4 "Elephas": 3,
5 "Giraffa": 8
6}
7
8# Sort by keys
9sorted_by_key = dict(sorted(species_count.items()))
10# {'Elephas': 3, 'Giraffa': 8, 'Leo': 12, 'Python': 5}
11
12# Sort by values
13sorted_by_value = dict(sorted(species_count.items(), key=lambda x: x[1]))
14# {'Elephas': 3, 'Python': 5, 'Giraffa': 8, 'Leo': 12}
15
16# Sort descending by values
17sorted_desc = dict(sorted(species_count.items(), key=lambda x: x[1], reverse=True))
18# {'Leo': 12, 'Giraffa': 8, 'Python': 5, 'Elephas': 3}Practical Example - Cataloging System
1# System for cataloging discovered species
2
3species_catalog = {}
4
5def add_species(name, common_name, habitat, dangerous, notes=""):
6 """Add a species to the catalog"""
7 species_catalog[name] = {
8 "common_name": common_name,
9 "habitat": habitat,
10 "dangerous": dangerous,
11 "notes": notes,
12 "discovery_date": "2024-11-24" # Example date
13 }
14 print(f"Added: {name}")
15
16def show_catalog():
17 """Display the entire catalog"""
18 if not species_catalog:
19 print("Catalog is empty!")
20 return
21
22 print(f"\n=== SPECIES CATALOG ({len(species_catalog)} entries) ===")
23 for name, data in species_catalog.items():
24 danger = "DANGEROUS" if data["dangerous"] else "Safe"
25 print(f"\n{name} ({data['common_name']})")
26 print(f" Habitat: {data['habitat']}")
27 print(f" Status: {danger}")
28 if data["notes"]:
29 print(f" Notes: {data['notes']}")
30
31def search_species(name):
32 """Search for a species by name"""
33 if name in species_catalog:
34 data = species_catalog[name]
35 print(f"\nFound: {name}")
36 print(f"Common name: {data['common_name']}")
37 print(f"Habitat: {data['habitat']}")
38 print(f"Dangerous: {'Yes' if data['dangerous'] else 'No'}")
39 else:
40 print(f"\nNot found: {name}")
41
42def filter_by_habitat(habitat):
43 """Filter species by habitat"""
44 filtered = {name: data for name, data in species_catalog.items()
45 if data["habitat"] == habitat}
46
47 print(f"\nSpecies in habitat '{habitat}': {len(filtered)}")
48 for name in filtered:
49 print(f" - {name}")
50
51# Using the system
52add_species("Python regius", "Royal Python", "jungle", False, "Calm species")
53add_species("Panthera leo", "Lion", "savanna", True, "Observe from a distance!")
54add_species("Gorilla gorilla", "Gorilla", "jungle", False)
55
56show_catalog()
57search_species("Python regius")
58filter_by_habitat("jungle")List vs Dictionary - When to Use Which?
Use a list when:
- Order is important
- You need access by numeric index
- You can have duplicates
- Simple collection of values
Use a dictionary when:
- You need fast access by key
- Each element has its own unique label
- Data has a key-value structure
- You want to easily check if an element exists
Practical Exercise
The editor holds the expedition register safari_registry. Complete it:
- Add the key
"vehicle"with the value"jeep" - Change
"budget_usd"to 20000 - Use
update()to add"species_found": 12and"photos_taken": 340 - Remove the key
"days_remaining"withdel
Code for this lesson: main.py
1# Adding and updating dictionary entries
2
3safari_registry = {
4 "expedition_name": "Serengeti 2024",
5 "leader": "Darwin",
6 "team_size": 5
7}
8
9print("Initial registry:")
10print(safari_registry)
11
12# Adding a new key
13safari_registry["location"] = "Tanzania"
14safari_registry["budget_usd"] = 15000
15
16# Updating an existing key
17safari_registry["team_size"] = 7
18
19print("\nAfter changes:")
20print(safari_registry)
21
22# update() - updates multiple keys at once
23safari_registry.update({
24 "status": "active",
25 "days_remaining": 14,
26 "leader": "Jane" # Overwrites existing
27})
28
29print("\nAfter update():")
30print(safari_registry)
31
32# TODO: Add key "vehicle" with value "jeep"
33
34
35# TODO: Change "budget_usd" to 20000
36
37
38# TODO: Use update() to add "species_found": 12 and "photos_taken": 340
39
40
41# TODO: Remove the key "days_remaining" using del
42# del safari_registry["?"]
43
44print("\nFinal registry:")
45for key, value in safari_registry.items():
46 print(f" {key}: {value}")
47Summary
In this lesson you learned:
- What dictionaries are (key-value pairs)
- Creating and accessing dictionaries
- Adding, modifying, removing elements
- Methods: keys(), values(), items(), get(), update(), setdefault()
- Dictionary comprehensions
- Nested dictionaries
- Iterating through dictionaries
- Sorting and operations on dictionaries
Checkpoint
Before moving on:
- You understand the difference between a list and a dictionary
- You can use get() instead of []
- You know items(), keys(), values()
- You can iterate through a dictionary
- You can create dict comprehensions
- You understand nested dictionaries
In the next lesson Darwin will show you tuples and sets - permanent records and a register of unique species!
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. A dictionary in Python stores:
2. How do you get the value of the key 'name' from the dictionary 'animal'?
3. What is the advantage of dict.get('key') over dict['key']?
4. What does dict.items() return?
Hands-on tasks in the game
- Click in order
Click the elements in the correct order:
- Code editor
Create a dictionary called 'tiger' with keys: name='Tiger', weight=200, dangerous=True
- Code editor
Print the name of the animal from the dictionary animal = {'name': 'Python', 'length': 5}
- Code editor
Add the key 'habitat' with the value 'Jungle' to the dictionary animal = {'name': 'Python', 'length': 5}
- Vertical ordering
Arrange the steps for building a catalog:
- Horizontal ordering
Arrange: animal = {'name': 'Tiger'}
- Click in order
Click in order: print(animal['name'])
- Vertical ordering
Arrange: create a dictionary, add a key, print all keys: