Featured image of post Using pure dictionary in Python is bad! Here are some alternatives and why you should use them

Using pure dictionary in Python is bad! Here are some alternatives and why you should use them

Why using pure dictionaries in Python is bad and what to use instead

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, or AttributeError, 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! 😊

Built with Hugo
Theme Stack designed by Jimmy