A dictionary is a collection that stores data as key–value pairs. Instead of accessing items by their position (index 0, index 1…), you access them by a meaningful name — a key. This makes dictionaries perfect for representing real-world objects: a spaceship has a name, a crew count, a fuel level, a hull rating. A list could store those four values, but a dictionary gives each one a label so you never have to remember which number means what.
1 Why Do We Need Dictionaries?
Suppose you are writing a program to track data about a spaceship. Using a list, you might write:
ship = ["Persephone", 12, 87.5, "operational"]
This works — but it is fragile. To get the fuel level, you have to remember that it is at index 2. Reorder the list and every piece of code that reads it breaks. Add a new field in the middle and all subsequent indices shift.
A dictionary solves this by giving each value a name:
ship = {
"name": "Persephone",
"crew": 12,
"fuel": 87.5,
"status": "operational"
}Now ship["fuel"] always means fuel level — no matter what order the fields are in, no matter how many new fields you add.
Imagine a physical logbook for a starship. Each entry has a labelled field: "Vessel name:", "Crew aboard:", "Fuel reserves:", "Mission status:". You do not look up the fuel level by counting to the third line — you look for the label "Fuel reserves:". A Python dictionary is this logbook: labelled fields you look up by name, not by position.
2 Creating a Dictionary
A dictionary is written with curly braces { }. Each entry is a key–value pair written as key: value, with pairs separated by commas.
ship = {
"name": "Persephone",
"class": "Firefly-class transport",
"crew": 12,
"fuel": 87.5,
"operational": True
}2.1 The Vocabulary of Dictionaries
| Term | What it means | Example |
|---|---|---|
| Dictionary | An unordered (in Python 3.7+ insertion-ordered) collection of key–value pairs. | {"name": "Persephone", "crew": 12} |
| Key | The label used to look up a value. Must be unique and immutable (usually a string or integer). | "name", "crew" |
| Value | The data stored under a key. Can be any type — string, int, float, bool, list, even another dictionary. | "Persephone", 12 |
| Key–value pair | One entry in the dictionary: a key and its associated value together. | "crew": 12 |
| Lookup | Retrieving a value by providing its key. | ship["crew"] → 12 |
2.2 Keys Must Be Unique
A dictionary cannot have two entries with the same key. If you define the same key twice, the second value silently overwrites the first — no error is raised:
ship = {
"fuel": 87.5,
"fuel": 42.0 # overwrites the first entry
}
print(ship["fuel"]) # 42.0Keys can be strings, integers, floats, or tuples — anything that cannot be changed after creation. They cannot be lists or other dictionaries (which are mutable). In practice, strings are by far the most common key type. Values, on the other hand, can be anything at all — including lists, other dictionaries, or None.
3 Accessing Values
3.1 Square Bracket Notation
Access a value by putting its key in square brackets, just like a list index — except you use a key name instead of a number:
ship = {
"name": "Persephone",
"crew": 12,
"fuel": 87.5
}
print(ship["name"]) # Persephone
print(ship["crew"]) # 12
print(ship["fuel"]) # 87.5If you ask for a key that does not exist — ship["weapons"] when there is no "weapons" key — Python raises a KeyError. This is the dictionary equivalent of an IndexError. Always make sure the key exists before accessing it, or use the safe .get() method described below.
3.2 The Safe Way: .get()
.get(key) returns the value for a key if it exists, or None if it does not — without raising an error. You can also provide a custom default value as a second argument:
ship = {"name": "Persephone", "crew": 12, "fuel": 87.5}
print(ship.get("crew")) # 12 — key exists
print(ship.get("weapons")) # None — key missing, no error
print(ship.get("weapons", "none")) # none — custom defaultUse square brackets [ ] when you are certain the key exists — for example, when you just created the dictionary yourself. Use .get() when the key might be absent — for example, when reading user-supplied data or merging dictionaries from different sources. Crashing with a KeyError because of a missing key is one of the most common dictionary bugs.
- What is the difference between accessing a list item and accessing a dictionary value?
Given this dictionary:
planet = {"name": "Kepler-22b", "distance_ly": 620, "habitable": True}What is the value of
planet["distance_ly"]? What happens if you tryplanet["moons"]?- Rewrite the unsafe access
ship["shields"]using.get()so that it returns0if the key is missing. - Why must dictionary keys be immutable? Give one example of a valid key and one example of an invalid key.
4 Adding and Modifying Entries
Dictionaries are mutable — you can add new key–value pairs and change existing values after creation. The syntax for both is the same: assignment using square brackets.
4.1 Modifying an Existing Value
ship = {"name": "Persephone", "fuel": 87.5, "crew": 12}
ship["fuel"] = 62.0 # fuel has dropped after a jump
ship["crew"] = 11 # one crew member disembarked
print(ship)
# {'name': 'Persephone', 'fuel': 62.0, 'crew': 11}4.2 Adding a New Key–Value Pair
If the key does not already exist, assignment creates it:
ship["shields"] = 95
ship["location"] = "Sector 7-G"
print(ship)
# {'name': 'Persephone', 'fuel': 62.0, 'crew': 11, 'shields': 95, 'location': 'Sector 7-G'}ship["fuel"] = 62.0 — Python checks: does the key "fuel" already exist? Yes → update it. No → create it. The same syntax handles both cases. This is intentional: Python keeps the operation simple and lets you focus on the data rather than whether a key is new or existing.
4.3 Updating Multiple Values: .update()
.update() merges another dictionary into the current one. Existing keys are updated; new keys are added:
ship = {"name": "Persephone", "fuel": 62.0, "crew": 11}
ship.update({"fuel": 100.0, "shields": 95, "location": "Starbase Omega"})
print(ship)
# {'name': 'Persephone', 'fuel': 100.0, 'crew': 11, 'shields': 95, 'location': 'Starbase Omega'}5 Removing Entries
| Method / Keyword | What it does | Returns |
|---|---|---|
del ship[key] | Removes the entry with that key. Raises KeyError if missing. | Nothing. |
ship.pop(key) | Removes the entry and returns its value. Raises KeyError if missing. | The removed value. |
ship.pop(key, default) | Removes the entry if it exists. Returns default if the key is missing — no error. | The removed value, or default. |
ship.clear() | Removes all entries, leaving an empty dictionary. | Nothing. |
ship = {
"name": "Persephone",
"fuel": 100.0,
"shields": 95,
"location": "Starbase Omega"
}
del ship["location"] # no longer tracking location
print(ship)
old_shields = ship.pop("shields") # remove and capture the old value
print("Removed shields rating:", old_shields)
removed = ship.pop("weapons", "not fitted") # safe remove — key may not exist
print("Weapons:", removed)- What is the difference between
del ship["key"]andship.pop("key")? Trace this code. What does
shipcontain after each line?ship = {"name": "Argo", "crew": 50, "fuel": 75.0, "shields": 80} ship["fuel"] = 90.0 ship["weapons"] = "plasma cannons" del ship["shields"] rating = ship.pop("crew") print(ship) print(rating)- Why is
ship.pop("weapons", None)safer thandel ship["weapons"]when you are not sure the key exists?
6 Testing for Membership
The in operator checks whether a key exists in a dictionary — the same operator you used for strings and lists in earlier articles. It always tests keys, never values.
ship = {"name": "Persephone", "fuel": 87.5, "crew": 12}
print("fuel" in ship) # True — the key "fuel" exists
print("weapons" in ship) # False — no such key
print("not" in ship) # False
print("fuel" not in ship) # FalseThis is the correct way to guard against a KeyError before accessing a key you are not sure about:
if "shields" in ship:
print("Shield strength:", ship["shields"])
else:
print("No shield data available.")"Persephone" in ship returns False — even though "Persephone" is a value in the dictionary. To check whether a value exists, you need "Persephone" in ship.values(). More on .values() in the next section.
- What does
intest when used with a dictionary — keys or values? Given
ship = {"name": "Argo", "crew": 50, "fuel": 75.0}, predictTrueorFalsefor each:"crew" in ship 50 in ship "weapons" not in ship "fuel" in ship
- Write a safe block of code that checks whether a key
"warp_drive"exists inshipbefore printing its value.
7 Iterating Through a Dictionary
Python gives you three views of a dictionary for iteration. Each is a live view of the dictionary's contents — not a copy — and each lets you loop over a different aspect of the data.
| Method | What you get | Use when… |
|---|---|---|
ship.keys() | All the keys. | You only need to know what fields exist. |
ship.values() | All the values. | You need to process every value but do not need the keys. |
ship.items() | All key–value pairs as tuples: (key, value). | You need both the key and the value together — the most common case. |
7.1 Iterating Over Keys
ship = {
"name": "Persephone",
"class": "Firefly",
"crew": 12,
"fuel": 87.5,
"shields": 95
}
for key in ship.keys():
print(key)Output:
name class crew fuel shields
Writing for key in ship: is identical to for key in ship.keys():. Iterating over a dictionary without specifying a view always iterates over keys. Using .keys() explicitly makes your intent clearer, which is good style — especially for beginners.
7.2 Iterating Over Values
for value in ship.values():
print(value)Output:
Persephone Firefly 12 87.5 95
7.3 Iterating Over Key–Value Pairs
This is the most useful form. .items() gives you both the key and the value together, which you unpack into two variables:
for key, value in ship.items():
print(f" {key:<10} : {value}")Output:
name : Persephone class : Firefly crew : 12 fuel : 87.5 shields : 95
7.4 Practical Iteration — Building a Status Report
fleet = [
{"name": "Persephone", "crew": 12, "fuel": 87.5, "shields": 95},
{"name": "Icarus IV", "crew": 8, "fuel": 43.0, "shields": 60},
{"name": "Calypso", "crew": 20, "fuel": 91.0, "shields": 88},
]
print("=== Fleet Status ===")
for ship in fleet:
status = "⚠ LOW FUEL" if ship["fuel"] < 50 else "OK"
print(f" {ship['name']:<15} crew: {ship['crew']:<4} "
f"fuel: {ship['fuel']:<6} shields: {ship['shields']} {status}")Output:
=== Fleet Status === Persephone crew: 12 fuel: 87.5 shields: 95 OK Icarus IV crew: 8 fuel: 43.0 shields: 60 ⚠ LOW FUEL Calypso crew: 20 fuel: 91.0 shields: 88 OK
- What is the difference between
.keys(),.values(), and.items()? Write a loop that prints every key–value pair in this dictionary, formatted as
"name → Persephone":ship = {"name": "Persephone", "crew": 12, "fuel": 87.5}- Given the fleet list above, write a loop that prints only the names of ships with shields below 70.
- A student writes
for item in ship:and expects to get both keys and values. What do they actually get, and how do they fix it?
8 Other Useful Dictionary Methods
| Method | What it does | Example | Result |
|---|---|---|---|
len(ship) | Returns the number of key–value pairs. | len({"a": 1, "b": 2}) | 2 |
ship.copy() | Returns a shallow copy. Same rules as list copying — assignment does not copy. | backup = ship.copy() | Independent copy. |
ship.setdefault(key, default) | Returns the value for key if it exists. If not, inserts key with default and returns default. | ship.setdefault("shields", 100) | 100 added if missing. |
dict() | Creates a dictionary from keyword arguments or an iterable of pairs. | dict(name="Argo", crew=50) | {"name": "Argo", "crew": 50} |
8.1 Copying a Dictionary
Just like lists, assigning a dictionary to a new variable does not create a copy — both variables point to the same object:
original = {"name": "Persephone", "fuel": 87.5}
alias = original # NOT a copy
alias["fuel"] = 0.0
print(original["fuel"]) # 0.0 — the original was changed too!Use .copy() to get a true independent copy:
original = {"name": "Persephone", "fuel": 87.5}
backup = original.copy()
backup["fuel"] = 0.0
print(original["fuel"]) # 87.5 — untouched9 Richer Data: Dictionaries Containing Lists
Values in a dictionary can be any type — including lists. This is how you naturally represent an object with multiple items in one of its fields:
ship = {
"name": "Persephone",
"crew": 12,
"fuel": 87.5,
"cargo": ["food supplies", "medical kits", "engine parts"],
"visited": ["Proxima Station", "New Shanghai", "Titan Outpost"],
}
# Access the whole list
print(ship["cargo"])
# ['food supplies', 'medical kits', 'engine parts']
# Access one item from the list
print(ship["cargo"][0])
# food supplies
# Add to the list
ship["cargo"].append("spare hull plating")
print(len(ship["cargo"])) # 4
# Check for an item in the list
if "medical kits" in ship["cargo"]:
print("Medical supplies confirmed aboard.")The notation ship["cargo"][0] reads left to right: first retrieve the value stored under "cargo" (which is a list), then access index 0 of that list.
- Given the
shipdictionary above, what doesship["visited"][-1]return? - Write a line that adds
"Kepler Colony"to the"visited"list insideship. - Write a loop that prints each item in
ship["cargo"]on its own line, numbered from 1.
10 Putting It All Together: The Fleet Management System
Here is a complete program that uses almost everything from this article. The data is a fleet of ships stored as a list of dictionaries. Read it carefully and trace a few of the function calls before running it.
FUEL_WARNING = 50.0 # global constant — low fuel threshold
SHIELD_WARNING = 70 # global constant — low shield threshold
# ── Fleet data ────────────────────────────────────────────────────
fleet = [
{
"name": "Persephone",
"class": "Firefly",
"crew": 12,
"fuel": 87.5,
"shields": 95,
"cargo": ["food supplies", "medical kits", "engine parts"],
},
{
"name": "Icarus IV",
"class": "Dreadnought",
"crew": 8,
"fuel": 43.0,
"shields": 60,
"cargo": ["weapons cache", "fuel cells"],
},
{
"name": "Calypso",
"class": "Science Vessel",
"crew": 20,
"fuel": 91.0,
"shields": 88,
"cargo": ["research equipment", "specimens", "data drives"],
},
]
# ── Functions ─────────────────────────────────────────────────────
def get_warnings(ship):
"""Returns a list of warning strings for a given ship dict."""
warnings = []
if ship["fuel"] < FUEL_WARNING:
warnings.append(f"LOW FUEL ({ship['fuel']}%)")
if ship["shields"] < SHIELD_WARNING:
warnings.append(f"LOW SHIELDS ({ship['shields']}%)")
return warnings
def print_ship_summary(ship):
"""Prints a one-line summary for a ship."""
warnings = get_warnings(ship)
flag = " ⚠ " + ", ".join(warnings) if warnings else ""
print(f" {ship['name']:<16} [{ship['class']}] "
f"crew: {ship['crew']:<4} "
f"fuel: {ship['fuel']:<6} "
f"shields: {ship['shields']}{flag}")
def find_ship(fleet, name):
"""Returns the ship dict with the given name, or None if not found."""
for ship in fleet:
if ship["name"].lower() == name.lower():
return ship
return None
def refuel(ship, amount):
"""Adds fuel to a ship, capped at 100.0. Returns the amount actually added."""
space = 100.0 - ship["fuel"]
added = min(amount, space)
ship["fuel"] = round(ship["fuel"] + added, 1)
return added
def fleet_cargo_contains(fleet, item):
"""Returns a list of ship names whose cargo contains the given item."""
carrying = []
for ship in fleet:
if item in ship["cargo"]:
carrying.append(ship["name"])
return carrying
# ── Main program ──────────────────────────────────────────────────
print("╔══════════════════════════════╗")
print("║ STARFLEET OPERATIONS HQ ║")
print("╚══════════════════════════════╝\n")
# Fleet overview
print("── Fleet Status ─────────────────────────────")
for ship in fleet:
print_ship_summary(ship)
# Find and refuel a specific ship
print("\n── Refuelling Operation ─────────────────────")
target = find_ship(fleet, "Icarus IV")
if target:
added = refuel(target, 70.0)
print(f" Transferred {added}% fuel to {target['name']}.")
print(f" New fuel level: {target['fuel']}%")
# Check cargo across the fleet
print("\n── Cargo Search ─────────────────────────────")
search_item = "medical kits"
ships_with_item = fleet_cargo_contains(fleet, search_item)
if ships_with_item:
print(f" '{search_item}' found aboard: {', '.join(ships_with_item)}")
else:
print(f" '{search_item}' not found in any ship's cargo.")
# Print all fields of one ship using .items()
print("\n── Detailed Report: Calypso ─────────────────")
calypso = find_ship(fleet, "Calypso")
for key, value in calypso.items():
print(f" {key:<10} : {value}")Things to notice:
get_warnings()iterates over nothing — it just accesses specific keys directly, usinginand comparisons.find_ship()loops over the fleet list, checkingship["name"]for each dictionary.fleet_cargo_contains()checksitem in ship["cargo"]— theinoperator working on a list that is itself a dictionary value.- The final loop uses
.items()to print every key–value pair of one ship's dictionary — a useful debugging technique.
11 Final Check: The Big Picture
A dictionary stores data as key–value pairs, accessed by meaningful names rather than by position. Access values with [ ] or the safer .get(). Add and modify entries with assignment; remove with del or .pop(). Test for key membership with in. Iterate with .keys(), .values(), or .items() — the last being the most useful. Assigning a dictionary to a new variable does not copy it. Dictionaries can hold any type of value, including lists and other dictionaries, making them the natural structure for representing real-world objects.
- In your own words: what is the core difference between a list and a dictionary? When would you choose each?
Trace this program completely. Write the state of
shipafter every line.ship = {"name": "Argo", "crew": 50, "fuel": 80.0} ship["shields"] = 100 ship["fuel"] -= 25.0 old_crew = ship.pop("crew") ship.update({"status": "patrol", "fuel": 90.0}) print(ship) print(old_crew)- Write a function called
is_combat_ready(ship)that takes a ship dictionary and returnsTrueonly if: the ship has a"shields"key, shields are 75 or above, and fuel is 40 or above. - Given a list of ship dictionaries called
fleet, write a loop that prints the name of every ship that carries"weapons cache"in its"cargo"list. This code is supposed to print a backup of
ship, then clear the original, but it prints an empty dictionary for both. Why? Fix it.ship = {"name": "Persephone", "fuel": 87.5} backup = ship ship.clear() print(backup)
12 Quick-Reference Summary
| Operation | Syntax | Notes |
|---|---|---|
| Create | d = {"key": value} | Curly braces, colon separates key and value, comma between pairs. |
| Access (unsafe) | d["key"] | Raises KeyError if the key does not exist. |
| Access (safe) | d.get("key", default) | Returns default (or None) if key is missing. No error. |
| Add / modify | d["key"] = value | Creates key if new; overwrites if existing. |
| Merge / update | d.update(other_dict) | Adds new keys; overwrites existing ones. |
| Remove (no return) | del d["key"] | Raises KeyError if missing. |
| Remove (with return) | d.pop("key", default) | Returns value. Safe with default argument. |
| Clear all | d.clear() | Empties the dictionary in place. |
| Membership (key) | "key" in d | Tests keys only, not values. |
| Membership (value) | value in d.values() | Use .values() to search values. |
| Iterate keys | for k in d.keys(): | Same as for k in d: |
| Iterate values | for v in d.values(): | Values only — no keys. |
| Iterate both | for k, v in d.items(): | Most common iteration pattern. |
| Length | len(d) | Number of key–value pairs. |
| Copy | d.copy() | b = a is NOT a copy — both point to the same dict. |