Dictionaries in Python are the go-to structure whenever you need to look up values by a meaningful key instead of a numeric position.
A dictionary is a Python data structure that stores values in pairs: each value is attached to a unique key, and you look the value up by that key rather than by its position, the way you would with a list. Think of a real paper dictionary: you don’t scan every page in order to find a word’s meaning, you jump straight to the word itself. Python dictionaries work the same way – the key is what you already know, and the value is what you’re looking up.
A dictionary is written inside curly braces, with each key and its value separated by a colon, and each pair separated by a comma.
student = {
'name': 'Ahmed',
'age': 22,
'city': 'Lahore'
}
print(student)
Keys are usually strings or numbers, and must be unique within a dictionary – assigning a value to a key that already exists overwrites the old value rather than creating a second entry. Values, on the other hand, can be absolutely anything: numbers, strings, lists, even other dictionaries.
You retrieve a value by placing its key in square brackets after the dictionary’s name.
student = {'name': 'Ahmed', 'age': 22, 'city': 'Lahore'}
print(student['name']) # Ahmed
There is a catch: if the key you ask for doesn’t exist, square-bracket access raises a KeyError and stops your program. This is where the dictionary’s get() method earns its keep. get() looks up a key the same way, but if the key is missing, it quietly returns None instead of crashing – or, if you pass a second argument, returns that value instead.
student = {'name': 'Ahmed', 'age': 22}
print(student.get('city')) # None
print(student.get('city', 'Unknown')) # Unknown
As a general habit, prefer get() over square brackets whenever a key might reasonably be missing, and save square-bracket access for cases where the key’s presence is guaranteed and a missing key would actually indicate a bug worth crashing on.
student = {'name': 'Ahmed', 'age': 22}
student['city'] = 'Lahore' # adds a new key
student['age'] = 23 # updates an existing key
del student['age'] # removes a key entirely
print(student)
Assigning to a key that doesn’t exist yet creates it; assigning to a key that already exists simply replaces its value. There is no separate “insert” operation the way there sometimes is in other languages – a dictionary in Python only ever has one way to set a value at a key.
A plain for loop over a dictionary walks through its keys by default. To get keys and values together, use the items() method, which returns each key-value pair as a tuple.
student = {'name': 'Ahmed', 'age': 22, 'city': 'Lahore'}
for key in student:
print(key)
for key, value in student.items():
print(key, ':', value)
for value in student.values():
print(value)
keys(), values(), and items() each return a view of the dictionary rather than a fixed copy – if the dictionary changes afterward, the view reflects that change automatically. Since Python 3.7, dictionaries also remember the order their keys were inserted in, so looping over one will always visit keys in that same insertion order, not some arbitrary order.
Just as a list comprehension builds a list in one line, a dictionary comprehension builds a dictionary the same way: {key_expression: value_expression for item in iterable}.
names = ['Ahmed', 'Sara', 'Bilal']
ages = [22, 27, 19]
student_ages = {name: age for name, age in zip(names, ages)}
print(student_ages)
adults = {name: age for name, age in student_ages.items() if age >= 21}
print(adults)
The first comprehension pairs up two separate lists into one dictionary using zip(); the second builds a filtered dictionary from an existing one by adding an if condition at the end, keeping only the entries that pass it.
How you combine two dictionaries into one depends on which version of Python you’re running, since this is an area where the language has kept adding cleaner syntax over time. All three approaches below produce the same result: a new dictionary containing every key from both, with values from the second dictionary winning whenever a key appears in both.
a = {'x': 1, 'y': 2}
b = {'y': 20, 'z': 30}
# Any version of Python 3
c = a.copy()
c.update(b)
# Python 3.5 and later
c = {**a, **b}
# Python 3.9 and later
c = a | b
print(c) # {'x': 1, 'y': 20, 'z': 30}
The | merge operator, added in Python 3.9, is the newest and generally the most readable of the three once you’re working on a codebase that doesn’t need to support older Python versions. There’s also an in-place version, a |= b, which updates a directly with everything from b rather than building a separate new dictionary.
The in keyword checks dictionary keys, not values, which occasionally surprises people coming from lists.
student = {'name': 'Ahmed', 'age': 22}
print('name' in student) # True (checks keys)
print('Ahmed' in student) # False (Ahmed is a value, not a key)
Because dictionaries look keys up directly rather than scanning through every entry, checking whether a key exists with in stays fast even as a dictionary grows very large – a property lists don’t share, since checking membership in a list means potentially scanning every single item.
No Comments