Definition and Creating Dictionaries
A dictionary is a mutable mapping from unique keys to values. You look up each item through a meaningful key such as a name, identifier, or date.
Ways to Create Dictionaries
Python provides several ways to create dictionaries, including empty ones and ones that already contain data.
# Creating empty dictionaries
a = {}
b = dict()
print("Empty dictionary a:", a)
print("Empty dictionary b:", b)
# Output: Empty dictionary a: {}
# Output: Empty dictionary b: {}
# Creating dictionary with data
phone = {'ann': 110, 'bob': 991, 'cat': 112, 'dan': 999}
print("Dictionary phone:", phone)
# Output: Dictionary phone: {'ann': 110, 'bob': 991, 'cat': 112, 'dan': 999}
# Creating nested dictionary
person = {1: {'name': 'ann', 'age': 23}, 2: {'name': 'bob', 'age': 21}}
print("Nested dictionary:", person)
# Output: Nested dictionary: {1: {'name': 'ann', 'age': 23}, 2: {'name': 'bob', 'age': 21}}
# Creating dictionary with constructor
month = dict([(1, 'Jan'), (2, 'Feb'), (3, 'Mar')])
mass = dict(Mercury=3.3e23, Venus=4.9e24, Earth=6.0e24)
print("Dictionary month:", month)
print("Dictionary mass:", mass)
# Output: Dictionary month: {1: 'Jan', 2: 'Feb', 3: 'Mar'}
# Output: Dictionary mass: {'Mercury': 3.3e+23, 'Venus': 4.9e+24, 'Earth': 6e+24}Dictionary Syntax
A dictionary display uses curly braces. Commas separate its entries, and a colon separates each key from its value. The empty display {} creates an empty dictionary.
# Basic dictionary syntax
phone = {'ann': 110, 'bob': 991, 'cat': 112, 'don': 999}
print(phone)
# Output: {'ann': 110, 'bob': 991, 'cat': 112, 'don': 999}Keys must be hashable. Strings and numbers are common choices. A tuple qualifies only when every element is also hashable. A tuple containing a list does not qualify. Lists themselves are not hashable. Values may be any Python object, including another dictionary.
Dictionary as Container
A dictionary is a container because it holds a collection of other objects. Its defining behavior is mapping each key to one value while preserving the order in which keys were first inserted.
Lists and tuples organize items by position, while dictionaries organize entries by key. This distinction determines how you read, update, and iterate through their contents.
Dictionary Characteristics
A dictionary is mutable, its keys are unique and hashable, and its iteration order follows key insertion order. Those three properties explain most of the behavior you observe later: why you can add or remove entries after creation, why assigning to an existing key overwrites instead of duplicating, and why iterating over a dictionary gives a stable, predictable order.
Insertion Order and Unique Keys
Python's language specification guarantees dictionary insertion order from Python 3.7 onward. Assigning a new value to an existing key updates that entry without moving the key. Deleting the key and inserting it again places it at the end.
# Insertion order is preserved
phone = {'ann': 110, 'bob': 991, 'cat': 112, 'bob': 999}
print(phone)
# Output: {'ann': 110, 'bob': 999, 'cat': 112}
# Key 'bob' stays in second position even though its value changedBecause keys are unique, a repeated key in a dictionary display keeps only its final assigned value. The surviving key retains the position established by its first occurrence.
Accessing Dictionaries
To retrieve a value from a dictionary, provide its key. A meaningful key such as a name or date takes the place of a sequential numeric index.
Indexing with Keys
# Accessing values with keys
phone = {'ann': 110, 'bob': 991, 'cat': 112, 'dan': 999}
# Retrieving values
print(phone['cat'])
# Output: 112
# Using variable as key
name = 'bob'
print(phone[name])
# Output: 991
# Adding or changing values
phone['bob'] = 999 # Change existing key value
phone['eve'] = 111 # Add new key
print(phone)
# Output: {'ann': 110, 'bob': 999, 'cat': 112, 'dan': 999, 'eve': 111}Square-bracket access retrieves an existing value. Assignment with brackets updates an existing key or appends a new key-value pair to the insertion order.
Dictionary Iteration
Choose the iteration form that matches whether you need keys alone, values alone, or both parts of each entry. Iterating a dictionary directly gives keys, calling .values() gives values, and calling .items() gives key-value pairs.
Iterating over Dictionary Keys
# Iterating dictionary keys
phone = {'ann': 110, 'bob': 999, 'cat': 112, 'dan': 999}
for key in phone:
print(key, phone[key])
# Output:
# ann 110
# bob 999
# cat 112
# dan 999When you iterate a dictionary directly, Python retrieves keys in their insertion order.
Iterating over Dictionary Entries
# Iterating key-value pairs with items()
phone = {'ann': 110, 'bob': 999, 'cat': 112, 'dan': 999}
for key, val in phone.items():
print(key, val)
# Output:
# ann 110
# bob 999
# cat 112
# dan 999The items() view yields each key and value together, so tuple unpacking can name both values in one loop.
Three Types of Dictionary Views
A dictionary exposes dynamic views of its keys, values, and key-value pairs. A view is not a copy: it reads the current contents of the dictionary every time you iterate it, so a change after the view was created shows up in the very next loop.
Creating Dictionary Views
# Using dictionary methods
phone = {'ann': 110, 'bob': 991, 'cat': 112, 'dan': 999}
# Getting all keys
keys = phone.keys()
print("Keys:", list(keys))
# Output: Keys: ['ann', 'bob', 'cat', 'dan']
# Getting all values
values = phone.values()
print("Values:", list(values))
# Output: Values: [110, 991, 112, 999]
# Getting key-value pairs
items = phone.items()
print("Items:", list(items))
# Output: Items: [('ann', 110), ('bob', 991), ('cat', 112), ('dan', 999)]
snapshot = list(keys)
phone['eve'] = 111
print(list(keys)) # Output: ['ann', 'bob', 'cat', 'dan', 'eve']
print(snapshot) # Output: ['ann', 'bob', 'cat', 'dan']These views support iteration, but not positional indexing or item assignment. Calling list() creates a snapshot of the current entries. A later key insertion appears in the view but not in the snapshot. If a value is mutable, the snapshot still holds a reference to that same object.
The Get Method
Use get() when a missing key is an expected case and you want a fallback value. Use bracket access when a missing key should be treated as an error.
Errors from Bracket Access to Missing Keys
# Problem accessing non-existing keys
phone = {'ann': 110, 'bob': 991, 'cat': 112, 'dan': 999}
try:
print(phone['pat'])
except KeyError as e:
print("KeyError:", e)
# Output: KeyError: 'pat'Indexing a dictionary with a non-existing key will result in a KeyError.
Solution with the Get Method
# Using get() method for safe access
phone = {'ann': 110, 'bob': 991, 'cat': 112, 'dan': 999}
# get() returns None if key doesn't exist
result = phone.get('pat')
print("Result get('pat'):", result)
# Output: Result get('pat'): None
# get() with default value
result = phone.get('pat', -1)
print("Result get('pat', -1):", result)
# Output: Result get('pat', -1): -1
# get() for existing key
result = phone.get('ann')
print("Result get('ann'):", result)
# Output: Result get('ann'): 110get() returns the stored value when the key exists. Otherwise it returns the supplied default, or None when no default is supplied. Choose a default that cannot be confused with a valid stored value when that distinction matters.