Dictionaries
Dictionaries are one of the most important data structures in Python — and they're everywhere. 📖 Even when you don't see them directly, they're often working behind the scenes, quietly holding things together.
For instance, while a string like "hello" isn’t itself a dictionary, many
Python objects (including strings) use internal dictionaries to store
attributes and metadata. And when you assign a = "my_name", you're creating
a name (a) that points to a string object — which, like most Python objects,
has a dictionary of attributes under the hood.
The real magic of dictionaries is association. Linking keys to values
(key: value) creates fast and flexible lookups. Want to find a user’s email
by their username? Dictionary. Want to count how many times something appears?
Dictionary.
If you’ve used other programming languages, you might have heard these referred to as associative arrays, hash maps, or just maps. It’s the same core idea: match a key to a value. Think of it like an old-school phone book — you know the name, and the dictionary gives you the number.
Dictionaries are a much less compute-intensive way to associate two values than say, keeping those values in two lists (where the order is guaranteed). In fact, the lookup speed of a dictionary is not affected by its size! ⚡ That's some serious performance.
Tip
Every key in a dictionary must be unique and hashable. In practical
terms, this means you can't use a mutable object as keys - so you can't
use a list or a dict as as a key in a dictionary. This will throw a
TypeError exception. Mutable objects can be assigned as values.
For example, trying to assign the list engine_parts with
dream_car['engine_parts'] = 563throws an error:
Traceback (most recent call last):
File "/home/brad/Documents/exploring_python/basics/data_structures/dictionaries.py", line 17, in <module>
dream_car[engine_parts] = 563
~~~~~~~~~~^^^^^^^^^^^^^^
TypeError: unhashable type: 'list'
The data type of a dictionary in Python is dict, and they're iterable, even
though they're not a sequence type like a list or set. In lists,
you can insert a value at a specific index position in the sequence. With
dictionaries, position is determined by insertion order—new items are always
appended to the end. When iterating over a dictionary (see below), iteration
will always happen in insertion order. This isn't an index, but the natural
order of dictionaries.
Info
Prior to Python v3.6, there was no guaranteed order of dictionaries at all.
As of v3.6, this changed, and dictionaries are guaranteed to iterate over
the insertion order.
Creating a Dictionary
Dictionaries can be declared with:
| Creating a Dictionary | |
|---|---|
To retrieve a value, use square brackets [] and supply a key (not an index
like a list):
Would return:
Inserting or Changing a Value
You can insert or update a key/value pair using the same square bracket syntax with an assignment:
| Inserting and Updating Key/Value Pairs | |
|---|---|
This would output:
Deleting a Key/Value Pair
Removing an entry is as easy as using the del keyword:
| Deleting a Key/Value Pair | |
|---|---|
Avoiding KeyError with get()
Attempting to read or delete a key that doesn’t exist will raise a KeyError
exception. For example, attempting to retrieve dream_car['engine'] would
result in:
Traceback (most recent call last):
File "exploring_python/basics/data_structures/dictionaries.py", line 19, in <module>
dream_car['engine']
~~~~~~~~~^^^^^^^^^^
KeyError: 'engine'
The dict.get() method tries to find a key in a dictionary and will not raise
an error if that key doesn't exist. Even better, you can assign a default value
to return if the key is missing (the default is None). So, if you search for
a key and it isn't present, the default value will be returned:
| Creating a Dictionary | |
|---|---|
Returns:
Tip
Note that the key/value pair engine: V8 isn't inserted into the
dictionary. Instead, this one-time value is returned to avoid throwing
a KeyError.
Clearing a Dictionary
If the data in a dictionary is no longer valuable, but you'd like to keep
the same dictionary object, use the clear() method to empty a dictionary
without changing the id.
| Clear a Dictionary but Keep the Object | |
|---|---|
Results in:
Dream Car Object ID: 140457216790016
Dream Car after clear: {}
Dream Car Object ID after clear: 140457216790016
Merging Dictionaries
Dictionaries often store related data, so merging them is a common task.
To do this, use the update() method. When you call update(), the
dictionary you pass in will merge with the original dictionary:
it will update any values with the same key and add any
key/value pairs that did not exist in the original dictionary.
| Merging Dictionaries | |
|---|---|
- The
update()method is also available, with similar functionality, insets
Would output:
Dream Car: {'model': 'Pinto', 'make': 'Ford', 'year': 1971, 'mileage': 400, 'engine': 'V8', 'horsepower': 440, 'cylinders': 8}
Dream Car Engine: {'engine': 'V8', 'horsepower': 440, 'cylinders': 8}
Note how dream_car_engine was not modified by the update() function,
only dream_car.
Merge Operator (Python 3.9+)
Python 3.9 introduced the | operator for merging dictionaries:
The setdefault() Method
setdefault() gets a value if the key exists, or sets it to a default if it doesn't:
This is particularly useful for building up collections:
| Building Lists in a Dict | |
|---|---|
Dictionary Comprehensions
Just like list comprehensions, you can create dictionaries with a concise syntax:
Practical Dict Comprehension Patterns
defaultdict: Dictionaries with Default Values
The defaultdict from the collections module automatically creates missing keys with
a default value. No more KeyError! 🎉
Common defaultdict Factories
Counter: Counting Made Easy
Counter is a specialized dict for counting hashable objects. Perfect for answering
questions like "How many times did someone order pepperoni?" (Spoiler: a lot. But at
least it wasn't on cheap pizza.)
Counter Operations
Iterating Over Dictionaries
Three ways to iterate, depending on what you need:
items() is Your Friend
When you need both key and value, always use items(). It's cleaner than
for key in dict: value = dict[key].
Key Takeaways
| Concept | What to Remember |
|---|---|
| Creating | {"key": value} or dict() |
| Accessing | dict[key] or dict.get(key, default) |
| Adding/Updating | dict[key] = value |
| Deleting | del dict[key] or dict.pop(key) |
| Merging | dict.update(other) or dict1 \| dict2 (3.9+) |
| setdefault() | Get or set a default in one step |
| Comprehensions | {k: v for k, v in items} |
| defaultdict | Auto-creates missing keys with a factory |
| Counter | Specialized dict for counting |
| Iteration | keys(), values(), items() |
| Order | Insertion order preserved (Python 3.7+) |