Are you a Python developer who loves to use dictionaries for everything?
Do you think that dictionaries are the ultimate data structure that can handle any kind of data?
Do you enjoy writing code like this?
user = {
"name": "John",
"age": 25,
"email": "john@example.com",
"address": {
"street": "123 Main Street",
"city": "New York",
"state": "NY",
"zip": "10001"
}
}
print(user["name"])
print(user["address"]["zip"])
If you answered yes to any of these questions, then this blog post is for you.
In this post, I will show you why using pure dictionaries in Python can be a bad idea, and what are some of the alternatives that can make your code more readable, maintainable, and bug-free. 🐛
Why pure dictionaries are bad
Don’t get me wrong, dictionaries are great for some use cases, such as storing key-value pairs, caching data, or implementing hash tables. But they are not suitable for representing complex data types, such as objects, records, or structs. Here are some of the reasons why:
-
No type hinting: Dictionaries have no type information, which means that you can store anything in them, and the compiler or the interpreter won’t complain. This can lead to runtime errors, such as
KeyError
,TypeError
, orAttributeError
, if you try to access a key that doesn’t exist, or a value that has a different type than expected. 😱 -
No validation: Dictionaries have no way of enforcing constraints on the data they store, such as required fields, default values, or data types. This means that you have to manually check and validate the data before using it, which can be tedious and error-prone. 😓
-
No methods: Dictionaries have no behavior associated with them, which means that you can’t define custom methods or functions that operate on them. This makes your code less expressive and more procedural, as you have to write separate functions that take dictionaries as arguments and return dictionaries as results. 😴
What are the alternatives
Fortunately, Python has several built-in or third-party modules that provide better alternatives to pure dictionaries for representing complex data types. Here are some of the most popular ones:
TypedDict
TypedDict is a feature introduced in Python 3.8 that allows you to define dictionary-like classes with type annotations. This way, you can specify the keys and values of your dictionaries, and use static type checkers like mypy
to catch errors at compile time. For example:
from typing import TypedDict
class Address(TypedDict):
street: str
city: str
state: str
zip: str
class User(TypedDict):
name: str
age: int
email: str
address: Address
user = User(
name="John",
age=25,
email="john@example.com",
address=Address(
street="123 Main Street",
city="New York",
state="NY",
zip="10001"
)
)
print(user["name"]) # John
print(user["address"]["zip"]) # 10001
NamedTuple
NamedTuple is a feature introduced in Python 3.6 that allows you to define immutable tuple-like classes with named fields. This way, you can access the elements of your tuples by name instead of by index, and use dot notation instead of brackets. For example:
from typing import NamedTuple
class Address(NamedTuple):
street: str
city: str
state: str
zip: str
class User(NamedTuple):
name: str
age: int
email: str
address: Address
user = User(
name="John",
age=25,
email="john@example.com",
address=Address(
street="123 Main Street",
city="New York",
state="NY",
zip="10001"
)
)
print(user.name) # John
print(user.address.zip) # 10001
Dataclass
Dataclass is a feature introduced in Python 3.7 that allows you to define mutable class-like objects with fields and methods. This way, you can add behavior to your data types, such as constructors, validators, or custom methods. For example:
from dataclasses import dataclass
@dataclass
class Address:
street: str
city: str
state: str
zip: str
def __str__(self):
return f"{self.street}, {self.city}, {self.state}, {self.zip}"
@dataclass
class User:
name: str
age: int
email: str
address: Address
user = User(
name="John",
age=25,
email="john@example.com",
address=Address(
street="123 Main Street",
city="New York",
state="NY",
zip="10001"
)
)
print(user.name) # John
print(user.address) # 123 Main Street, New York, NY, 10001
Conclusion
In this blog post, I have shown you why using pure dictionaries in Python can be a bad idea, and what are some of the alternatives that can make your code more readable, maintainable, and bug-free.
I hope you have learned something new and useful, and that you will give these alternatives a try in your next Python project. 🚀
If you want to learn more about static type checking in Python, I recommend you to check out the official documentation of mypy
, which is a popular tool for type checking Python code. You can find it here: https://mypy.readthedocs.io/en/stable/
(or wait for my blog post about it, lol)
Thank you for reading, and happy coding! 😊