14  Dictionaries

14.1 The Wall

AI used a dictionary when a list would have worked, and you did not know enough to question it. In another case, your code crashed with KeyError: 'username' because the dictionary did not have the key AI assumed existed. You had no idea how to check whether a key exists before accessing it.

Dictionaries are how AI organises structured data, user profiles, configuration, API responses, keyword mappings. If you cannot read dictionary operations, you cannot work with most real-world AI-generated code.

This chapter fixes that.

NoteComing from Think Python?

You may recognise dictionaries from the Contact Book project in Think Python, Direct AI, where you used them to store names and phone numbers. Here we explore dictionaries more thoroughly, how they work, the full range of methods, and the patterns that make them essential.

14.2 Thinking Session

14.2.1 Getting Oriented

NoteThinking Session Prompt

Explain Python dictionaries. How are they different from lists? When should I use a dictionary instead of a list? And what actually happens when I write user = {"name": "Alice", "age": 30}, how does Python find values by key?

Your AI should explain: dictionaries map keys to values, lists map indexes to values. Use a dictionary when you need to look things up by name, not by position. Keys must be immutable (strings, numbers, tuples) and unique. If your AI does not mention that dictionaries are unordered in older Python but ordered by insertion in Python 3.7+, that is a useful detail.

14.2.2 Go Deeper

NoteThinking Session Prompt

What are the most important dictionary methods? I see AI using get(), keys(), values(), items(), update(), and pop(). Explain each one. Specifically, what is the difference between user["name"] and user.get("name"), and why does AI sometimes use one versus the other?

TipWhat to Look For

The critical difference: user["name"] raises KeyError if the key does not exist. user.get("name") returns None (or a default you specify). AI should use .get() for keys that might not exist. If your AI does not emphasise this, it is the single most important dictionary concept.

NoteThinking Session Prompt

How do I loop through a dictionary in Python? What do I get when I use a for loop directly on a dictionary? And what is the items() method for?

14.2.3 Challenge It

NoteThinking Session Prompt

What happens with each of these?

data = {"a": 1, "b": 2}
data["c"]
data.get("c")
data.get("c", 0)
"a" in data
1 in data
data["a"] = 10
data.update({"b": 20, "d": 4})
TipWhat to Look For

data["c"] raises KeyError. data.get("c") returns None. data.get("c", 0) returns 0. "a" in data is True (checks keys). 1 in data is False (1 is a value, not a key). data["a"] = 10 updates the value. data.update(...) merges two dictionaries.

14.2.4 What You Should Have Learned

  • Dictionaries map keys to values: {"key": value}
  • Use dict[key] when you know the key exists, .get(key) when you do not
  • in checks keys, not values
  • items() gives key-value pairs for looping
  • Keys must be immutable; values can be anything
  • Dictionaries are mutable. You can add, change, and remove entries

14.3 The Gap

Dictionaries are how your chatbot will map keywords to responses, instead of long if/elif chains, you look up the response by category. This is the pattern AI uses in most structured programs: configuration as dictionaries, response templates as dictionaries, user data as dictionaries.

In the Building Session, you will replace the if/elif response logic with a dictionary-based approach.

14.4 Building Session

14.4.1 The Spec

Restructure your chatbot’s responses using dictionaries:

  • Map response categories to lists of possible responses
  • Map keywords to categories
  • Use .get() with a default for unknown categories
  • Add a “topics” command that shows all known categories

14.4.2 Prompt It

NoteBuilding Session Prompt

Update my chatbot to v1.4. Replace the if/elif response chain with dictionaries:

  • Create a RESPONSES dict mapping categories (“greeting”, “question”, “farewell”, “default”) to lists of response strings
  • Create a KEYWORDS dict mapping trigger words to categories (e.g., “hello” → “greeting”, “bye” → “farewell”)
  • Write a classify_input(text) function that checks each word against KEYWORDS and returns the category (default to “default”)
  • Update get_response() to use the dictionaries instead of if/elif
  • Add a “topics” command that shows all response categories and their keyword triggers

Keep existing features.

14.4.3 Read the Code

Your AI will produce something like this:

RESPONSES = {
    "greeting": [
        "Hello! Great to hear from you.",
        "Hi there! What's on your mind?",
    ],
    "question": [
        "Good question! Let me think...",
        "That's interesting. I'm learning too.",
    ],
    "farewell": [
        "Goodbye! It was nice chatting.",
        "See you later!",
    ],
    "default": [
        "Tell me more about that.",
        "Interesting! Go on...",
    ],
}

KEYWORDS = {
    "hello": "greeting",
    "hi": "greeting",
    "hey": "greeting",
    "bye": "farewell",
    "goodbye": "farewell",
    "quit": "farewell",
}


def classify_input(text):
    """Map input to a response category."""
    words = text.lower().split()
    for word in words:
        if word in KEYWORDS:
            return KEYWORDS[word]
    if "?" in text:
        return "question"
    return "default"


def get_response(user_input):
    """Get a response using dictionary lookup."""
    category = classify_input(user_input)
    responses = RESPONSES.get(category, RESPONSES["default"])
    return random.choice(responses), category == "farewell"
TipWhat to Notice

The if/elif chain is gone, replaced by dictionary lookups. Adding a new response category means adding entries to RESPONSES and KEYWORDS, not modifying logic. RESPONSES.get(category, RESPONSES["default"]) uses .get() with a fallback. This is how AI structures most configurable systems.

14.4.4 Stretch It

NoteBuilding Session Prompt

Add a “learn” command that lets the user teach the bot a new keyword-category mapping. Store it in the KEYWORDS dictionary. Test it by teaching a new keyword and then using it.

14.5 Your Chatbot So Far

  • Ch 1-12: Full features with functions, loops, text processing
  • Ch 13: String pattern matching
  • Ch 14: Dictionary-based responses, keyword classification, configurable categories

14.6 Quick Reference

# Create
user = {"name": "Alice", "age": 30}
empty = {}

# Access
user["name"]                # "Alice" (KeyError if missing)
user.get("name")            # "Alice" (None if missing)
user.get("role", "guest")   # "guest" (default)

# Modify
user["email"] = "a@b.com"   # add/update
user.update({"age": 31})    # merge
del user["age"]              # delete
user.pop("age", None)        # delete (no error if missing)

# Check
"name" in user               # True (checks keys)

# Loop
for key in user:             # keys only
for key, value in user.items():  # both
for value in user.values():      # values only

# Comprehension
squares = {x: x**2 for x in range(5)}