Python Dictionaries — Silent Key Overwrites in Merges
dict.
- A Python dictionary stores data in key-value pairs, like a phonebook mapping names to numbers
- Keys must be immutable (strings, numbers, tuples); values can be anything
- Access via square brackets throws KeyError; .get() returns None or a default safely
- Lookups are O(1) average thanks to hash tables—instant regardless of dictionary size
- In production, avoid modifying a dictionary while iterating over it or risk RuntimeError
- Biggest mistake? Using a mutable type (like a list) as a key—you get TypeError immediately
Every app you've ever used is quietly powered by key-value pairs. When you log into a website, your username is looked up in a giant table to find your password hash. When Spotify loads your profile, it fetches your name, playlist count, and subscription tier all at once — not as a pile of unconnected numbers, but as named, organised data. Python dictionaries are the building block that makes this kind of organised, instant-access data possible in your own code.
Before dictionaries existed in Python (or before programmers reached for them), people stored related data in parallel lists — one list of names, one list of phone numbers, hoping the indexes stayed in sync. This is fragile, confusing, and breaks the moment someone inserts a row in the wrong place. A dictionary solves this by gluing the label and the value together permanently, so they can never drift apart.
By the end of this article you'll know how to create a dictionary from scratch, read and update values safely, loop through it without breaking anything, and avoid the three mistakes that trip up almost every beginner. You'll also know exactly when a dictionary is the right choice — and when it isn't.
Creating Your First Dictionary — and Understanding What You're Actually Building
A dictionary in Python is written with curly braces {}. Inside, you place pairs of items separated by a colon — the thing on the left of the colon is the key, the thing on the right is the value. Each pair is separated from the next by a comma.
Think of it this way: the key is the label on a filing cabinet drawer, and the value is the document inside. You always open the drawer by its label — never by guessing which drawer number it is.
Keys must be unique. You can't have two drawers with the same label — Python would just keep the last one you defined and silently drop the earlier one. Keys must also be immutable (unchangeable), which in practice means they're almost always strings or numbers. Values, on the other hand, can be absolutely anything: a number, a string, a list, even another dictionary.
You can also create an empty dictionary with just {} and fill it in later — useful when you're building data dynamically, like reading lines from a file.
Reading, Adding, and Updating Values — The Three Core Operations You'll Use Every Day
Once your dictionary exists, you need to pull data out of it. The basic way is square bracket notation: student["name"] — think of it as typing the drawer label to pop it open.
But there's a trap with square brackets: if the key doesn't exist, Python throws a KeyError and your program crashes. The safer approach is the .get() method, which returns None by default (or a fallback value you choose) instead of crashing. In production code, .get() is almost always the right choice.
Adding a new key-value pair looks identical to updating an existing one — dictionary["new_key"] = value. If the key already exists, the value gets replaced. If it doesn't exist yet, a new pair is created. Python handles both cases with the same syntax, which keeps things simple.
Deleting a pair uses del dictionary["key"] or the .pop() method. The advantage of .pop() is that it returns the value you removed, so you can use it before it's gone — handy when you're moving data between structures.
Looping Through a Dictionary — Keys, Values, and Both at Once
Looping over a dictionary is something you'll do constantly — printing a report, transforming data, searching for a specific value. Python gives you three clean methods for this, and knowing which one to use when is a mark of a confident Python developer.
Looping with just for key in dictionary gives you the keys only — the drawer labels. From each key you can look up the value inside the loop if you need it.
The .values() method gives you just the values, no keys — useful when you want to sum up prices or check if a specific value exists anywhere.
The real power move is .items(), which gives you both the key and the value as a pair on every iteration. This is what you'll use 80% of the time because you usually need both. Python unpacks the pair into two variables automatically — for key, value in dictionary.items() — and it reads almost like plain English.
Dictionaries in Python 3.7 and later also maintain insertion order, so the loop will always visit pairs in the order you added them.
Nested Dictionaries — Storing Complex, Real-World Data Structures
Real data is rarely flat. A user doesn't just have a name — they have an address, which itself has a street, city, and postcode. A dictionary can hold another dictionary as a value, letting you model this hierarchy naturally.
This is called a nested dictionary. You access values inside it by chaining square brackets or .get() calls: user["address"]["city"]. Each set of brackets digs one level deeper — like opening a folder inside a folder.
Nested dictionaries are everywhere in professional Python: JSON data from an API is almost always a nested dictionary (Python's json module converts it automatically). Configuration files, database records, and game state are all commonly stored this way.
One thing to watch when working with nested data: if an intermediate key doesn't exist, chaining square brackets will crash on the first missing key before it even tries the inner one. Using .get() at each level prevents this — or you can use a try/except block if the structure is deeply uncertain.
Dictionary Comprehensions — Build Dictionaries in One Line
Python's dictionary comprehension is a concise way to generate dictionaries from iterables. The syntax is {key: value for item in iterable}. It's the dict equivalent of list comprehensions — and just as powerful.
You can filter items with an if clause at the end. You can also use two for clauses to flatten nested data into a dictionary. Comprehensions are almost always faster than manual loops because they run at C speed inside the interpreter.
But beware: if the comprehension produces duplicate keys, the later one wins — silently. This makes them risky when the key-generating expression isn't guaranteed unique.
| Feature / Aspect | Python Dictionary | Python List |
|---|---|---|
| How you access data | By a named key: dict['name'] | By a position number: list[0] |
| Order guaranteed? | Yes — insertion order kept (Python 3.7+) | Yes — always ordered by index |
| Lookup speed | O(1) — instant, regardless of size | O(n) — slower as the list grows (for searching) |
| Duplicate keys allowed? | No — last assignment wins silently | Yes — duplicate values are fine |
| Best used when | You need to label your data (name, price, id) | You have a sequence of similar items (scores, names) |
| Key types allowed | Immutable only: strings, numbers, tuples | Not applicable — lists use integer indexes |
| Memory usage | Slightly higher due to hash table overhead | Lower — compact sequential storage |
Key Takeaways
- A dictionary stores data as key-value pairs — use it any time your data has labels (name, price, id) rather than just a sequence of items.
- Always use .get() instead of square brackets when the key might not exist — it prevents KeyError crashes and lets you define a sensible fallback value.
- Dictionary lookups are O(1) — Python uses a hash table internally, meaning it jumps directly to the value regardless of how many pairs are stored.
- Nested dictionaries (a dictionary inside a dictionary) are the natural way to model real-world hierarchical data like users, addresses, or JSON API responses.
- Dict comprehensions are faster and more readable than manual loops for building dictionaries from iterables.
Common Mistakes to Avoid
- Using a mutable type (like a list) as a dictionary key
Symptom: You get `TypeError: unhashable type: 'list'` immediately. The program crashes before it can process any data.
Fix: Convert the list to an immutable tuple first: usetuple([1,2,3])as the key instead of[1,2,3]. - Accessing a key that might not exist with square brackets instead of .get()
Symptom: A `KeyError` crashes your program, especially painful when processing user input or API responses where keys are not guaranteed.
Fix: Switch to.get('key', fallback_value)— it returnsNone(or your chosen default) instead of crashing. - Modifying a dictionary while iterating over it
Symptom: Python raises `RuntimeError: dictionary changed size during iteration` if you add or delete keys inside a `for key in dictionary` loop.
Fix: Iterate over a snapshot of the keys:for key in list(— this creates a static copy so adding or removing from the original dictionary during the loop is safe.dictionary.keys())
Interview Questions on This Topic
- QWhat's the difference between dict['key'] and dict.get('key'), and when would you choose one over the other in production code?JuniorReveal
- QDictionaries are described as O(1) for lookups — can you explain why that's the case, and what data structure Python uses under the hood to achieve it?Mid-levelReveal
- QIf you have two large lists — one of employee names and one of their salaries — and you need to frequently look up a salary by name, how would you restructure this data and why?JuniorReveal
Frequently Asked Questions
Can a Python dictionary have duplicate keys?
No — dictionary keys must be unique. If you define the same key twice, Python doesn't raise an error; it silently keeps the last value assigned to that key and discards the earlier one. This is a common source of subtle bugs, so always make sure your keys are distinct.
What types can be used as dictionary keys in Python?
Only immutable (unchangeable) types can be keys — strings, integers, floats, and tuples are all valid. Lists and dictionaries cannot be keys because they can be changed after creation, which would break Python's internal hash table. If you need a sequence as a key, convert it to a tuple first.
Is a Python dictionary ordered? Will my keys always come back in the same order?
Yes, from Python 3.7 onwards dictionaries are guaranteed to maintain insertion order — the order you added the key-value pairs is the order you'll get them back when you loop or print. In Python 3.6 and earlier this was not guaranteed, so if you're on a modern Python version (which you almost certainly are), you can rely on insertion order.
That's Data Structures. Mark it forged?
4 min read · try the examples if you haven't