Master Guide to Dictionaries in Python: Key-Value Mappings and Iteration

Hello Everyone! Today we are exploring Dictionaries in Python.

A dictionary is a collection of items stored as key-value pairs. It acts like a real-world dictionary or phonebook: you look up a unique, unchangeable terminal identifier (the Key) to immediately access its matching description or structural payload (the Value).

1. What is a Dictionary?

  • Ordered: Dictionaries preserve insertion order. The order in which you add key-value pairs remains fixed during execution.
  • Mutable: You can add, remove, and alter key-value pairs dynamically in-place.
  • Unique Keys: Keys must be completely unique. If you try to re-use an existing key during setup, the newer entry overwrites the older value.
  • Immutable Keys: Keys must belong to a hashable / immutable data type (strings, integers, floats, or tuples). Mutable sequences like lists or sets cannot be keys.
  • Values Can Be Anything: Values have zero data type restrictions and can freely duplicate.
# A mixed-type dictionary
mixed_keys_dict = {
     "name": "Bob",
     1: "one",
     3.14: "pi",
     (1, 2): "tuple key" # Valid: Tuples are immutable
}

Initializing Dictionaries

# 1. Literal Bracket Syntax
empty_dict = {}

# 2. Using the dict() Constructor
# Note: When using dict(), keys are passed as named keyword arguments without quotes
student = dict(name="Charlie", id=101, grade="A") 
print(student) # Output: {'name': 'Charlie', 'id': 101, 'grade': 'A'}


2. Accessing Elements Safely

Python offers two distinct ways to look up your data values:

Method A: Square Bracket Indexing (dict[key])

This performs a quick lookup. However, if the requested key doesn’t exist, **the script crashes with a KeyError**.

profile = {"name": "Berlin", "age": 30}
print(profile["name"])  # Output: Berlin
# print(profile["mobile"]) # Crashes with KeyError!

Method B: The Safe .get(key, default=None) Method

This lookup alternative prevents crashes. If the key is missing, it returns None (or a custom default message you specify) instead of throwing an error.

print(profile.get("mobile"))                 # Output: None (Safe!)
print(profile.get("mobile", "Not Found"))    # Output: Not Found

company = {
     "employees": {
          "102": {
               "name": "Priya",
               "role": "Designer"
          }
     },
     "departments": ["HR", "Engineering", "Design"]
}

# Chain lookups together step-by-step
print(company.get("employees").get("102").get("name")) # Output: Priya
print(company.get("departments")[-1])                 # Output: Design


3. Modifying & Deleting Entries

grades = {"math": 90, "science": 85}

# Add a brand-new entry
grades["history"] = 78 

# Modify an existing key-value entry in-place
grades["math"] = 95 
print(grades) # Output: {'math': 95, 'science': 85, 'history': 78}

Evicting and Purging Data

  • del dict[key]: Permanently deletes a key-value entry. Throws a KeyError if the key is missing.
  • .pop(key, default): Removes a key and returns its value. If the key is missing, it returns your custom default.
  • .popitem(): Removes and returns the last inserted key-value pair as a (key, value) tuple.
  • .clear(): Empties out the entire dictionary structure.
grades = {"math": 95, "science": 85, "art": 92}

del grades["science"] # Removes science

popped_val = grades.pop("math")
print(popped_val)     # Output: 95

last_pair = grades.popitem()
print(last_pair)      # Output: ('art', 92)


4. Fundamental Dictionary Methods

Merging Databases with .update()

d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}

# Merges d2 directly into d1. Conflicting keys (like "b") get overwritten by d2's values.
d1.update(d2)
print(d1) # Output: {'a': 1, 'b': 3, 'c': 4}

Safe Fallbacks with .setdefault()

If a key already exists, .setdefault() returns its existing value. If the key is missing, it adds the key with your specified fallback value.

data = {"name": "Mohan"}
email = data.setdefault("email", "unknown@example.com")
print(data) # Output: {'name': 'Mohan', 'email': 'unknown@example.com'}

Global Keys, Values, and Items Iteration Views

person = {"name": "Mohan", "age": 30, "city": "New York"}

print(person.keys())   # View of all unique keys
print(person.values()) # View of all raw values
print(person.items())  # View of all key-value pairings as (key, value) tuples


5. Iterating and Loop Transformations

Iterating Over Dictionaries

person = {"name": "Mohan", "age": 30, "city": "New York"}

# 1. Iterating over keys directly
for key in person:
     print(key, person[key])

# 2. Unpacking keys and values together with .items()
for key, value in person.items():
     print(f"Key: {key} -> Value: {value}")

Inverting a Dictionary (Swapping Keys & Values)

# Construct a new flipped mapping on the fly using loops
flipped_data = {}
for key, value in person.items():
     flipped_data[value] = key

print(flipped_data) # Output: {'Mohan': 'name', 30: 'age', 'New York': 'city'}

Rebuilding Lists into Dictionaries

You can convert pairs from nested structures directly into a clean dictionary if they are in standard sequence alignments:

matrix_data = [["USA", "Washington"], ["France", "Paris"]]
countries = dict(matrix_data)
print(countries) # Output: {'USA': 'Washington', 'France': 'Paris'}


6. The enumerate() Loop Utility

When iterating over an array sequence, you often need access to both the character index track position and its current string value. The built-in enumerate() function wraps your tracking automatically:

fruits = ["apple", "banana", "cherry"]

# Loop unpacks index integer and list item simultaneously
for index, item in enumerate(fruits):
     print(f"Position Index {index} holds product element: {item}")