# Entry
Python dictionaries are useful for everything from configuration, JSON data, and API responses. Most beginners only learn the basics, such as creating a dictionary, accessing a key, and updating a value. That’s all. However, dictionaries offer much more. In this article we will discuss it 7 tips to make your code cleaner and more Pythonic. So let’s get started.
# Using .get() Instead [] to search
Let’s assume you’re working with a dictionary and you need to access values. But what if the key isn’t there? Let’s assume we have a configuration dictionary and you are trying to print a file "timeout" key like this:
config = {"debug": True, "verbose": False}
print(config["timeout"])
Exit:
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
----> 2 print(config["timeout"])
KeyError: 'timeout'
This will fail. You will receive KeyError Because "timeout" it’s not in the dictionary. You should utilize instead .get() method. This is more secure and you can set the default value if the key is missing.
config = {"debug": True, "verbose": False}
print(config.get("timeout", 30))
Exit:
This will be printed 30i.e. the default value that we set. However, if the missing key is an error, utilize square brackets. In this case, you want the error to appear immediately.
# Using defaultdict for grouping data
If you’re working with a list of words and want to count how many times each word appears, you can encode it like this:
words = ["apple", "banana", "apple", "cherry", "banana", "banana"]
counts = {}
for word in words:
if word not in counts:
counts[word] = 0
counts[word] += 1
print(counts)
Exit:
{'apple': 2, 'banana': 3, 'cherry': 1}
It works, but is a bit verbose. Python default verdict makes it cleaner:
from collections import defaultdict
words = ["apple", "banana", "apple", "cherry", "banana", "banana"]
counts = defaultdict(int)
for word in words:
counts[word] += 1
print(counts)
Exit:
defaultdict(, {'apple': 2, 'banana': 3, 'cherry': 1})
Because we used defaultdict(int)Python automatically creates a default value 0 each time the missing key is accessed.
# Combining dictionaries with | Operator
In up-to-date Python, the cleanest way to combine dictionaries is to utilize method | operator.
defaults = {"color": "blue", "size": "medium"}
overrides = {"size": "large", "weight": "heavy"}
merged = defaults | overrides
print(merged)
Exit:
{'color': 'blue', 'size': 'huge', 'weight': 'bulky'}
When keys overlap, the dictionary on the right wins. If you want to merge in place, you can utilize the method |= operator:
defaults |= overrides
print(defaults)
Exit:
{'color': 'blue', 'size': 'huge', 'weight': 'bulky'}
# Unpacking dictionaries into function arguments
Suppose you have a function and a dictionary, and their fields or keys match. Instead of passing the keys one by one, e.g name=data["name"], age=data["age"]you can pass anything with ** double star operator. Let’s create a user function and dummy user data to understand this:
def create_user(name, age, role="viewer"):
return {"name": name, "age": age, "role": role}
user_data = {
"name": "David",
"age": 33
}
# Normal Way
user = create_user(
name=user_data["name"],
age=user_data["age"],
role=user_data["role"]
)
print(user)
Exit:
{'name': 'David', 'age': 33, 'role': 'viewer'}
# Using **
print(create_user(**user_data))
Exit:
{'name': 'David', 'age': 33, 'role': 'viewer'}
Note that the “Normal Way” example above will output a >KeyError Because user_data does not contain A "role" key. The ** the unpacking approach correctly returns the function to its default value rolemaking it cleaner and more solid.
# Using the Walrus operator with plywood
Python 3.8 introduced the walrus operator (:=), which allows you to assign a value as part of an expression. This is very useful for dictionaries.
Suppose you have a dictionary and you want to get the user’s details and username, if any. You usually code it like this:
data = {
"user": {
"name": "Bryan",
"email": "bryan@gmail.com"
}
}
if data.get("user") is not None:
user = data.get("user")
name = user.get("name")
print(name)
Exit:
This works, but it repeats the same dictionary search multiple times. You can replace it with the walrus operator (:=), which finds and assigns a value in one step:
if (user := data.get("user")) is not None:
name = user.get("name")
print(name)
Exit:
This is especially useful when working with nested dictionary structures.
# Using TypedDict for structured data
Dictionaries are versatile, but this flexibility can sometimes become a problem. For example:
def greet(user):
return f"Hello, {user['name']}!"
user = {
"name": "Clair",
"age": "thirty"
}
print(greet(user))
Exit:
This works at runtime, but there is a hidden problem: "age" should be a number, not a string of characters. Python itself will not complain, which can later lead to bugs in larger projects. Dictation entered makes the expected dictionary structure explicit:
from typing import TypedDict
class UserProfile(TypedDict):
name: str
age: int
def greet(user: UserProfile) -> str:
return f"Hello, {user['name']}!"
Now tools like myps can catch errors before running the code:
user: UserProfile = {
"name": "Clair",
"age": "thirty",
}
print(greet(user))
Exit:
test.py:15: error: Incompatible types (expression has type "str", TypedDict item "age" has type "int") [typeddict-item]
Found 1 error in 1 file (checked 1 source file)
For more elaborate validation, tools such as dataclasses Or Pydantic are often a better choice.
# Iterate easily: .items(), .keys(), .values()
Python dictionaries have many built-in iteration methods: .items(), .keys()AND .values(). Most developers know about them but don’t utilize them as often as they should. They can loop the dictionary like this:
scores = {
"David": 92,
"Bryan": 87,
"Clair": 95
}
for name in scores:
print(name, scores[name])
Exit:
David 92
Bryan 87
Clair 95
It works. However, this is not the best way – an additional dictionary lookup is performed each time the loop is passed. Python .items() the method is cleaner:
for name, score in scores.items():
print(name, score)
Exit:
David 92
Bryan 87
Clair 95
It returns the key and value at the same time, which avoids multiple lookups and makes the code more readable. If you only need keys, utilize .keys() Instead. Similarly, if you only need the value, utilize .values().
# Summary
Python dictionaries seem uncomplicated at first glance, but learning a few key patterns can make your code much cleaner. You can utilize this to combine to learn more about Python dictionary-related features. Features like .get(), defaultdictunpacking i TypedDict aid reduce repetitive code and enhance program reliability.
Kanwal Mehreen is a machine learning engineer and technical writer with a deep passion for data science and the intersection of artificial intelligence and medicine. She is co-author of the e-book “Maximizing Productivity with ChatGPT”. As a 2022 Google Generation Scholar for APAC, she promotes diversity and academic excellence. She is also recognized as a Teradata Diversity in Tech Scholar, a Mitacs Globalink Research Scholar, and a Harvard WeCode Scholar. Kanwal is a staunch advocate for change and founded FEMCodes to empower women in STEM fields.
