avatarTimur Bakibayev, Ph.D.

Summary

The context discusses the differences between frozen and non-frozen dataclasses in Python and explains how to write and use frozen dataclasses.

Abstract

The context explains the concept of frozen dataclasses in Python, which are immutable objects that cannot be changed after creation. It provides an example of a Bank Account dataclass that is initially mutable, and then shows how to transform it into a frozen dataclass by adding the "frozen=True" argument to the dataclass decorator. The context then explains how to modify a frozen dataclass by returning a new object with the desired changes, instead of modifying the existing object. The author suggests that frozen dataclasses are useful for enforcing strict logic and avoiding unintended modifications to objects.

Opinions

  • The author suggests that frozen dataclasses are useful for enforcing strict logic and avoiding unintended modifications to objects.
  • The author notes that while Python does not have a strict concept of immutability, frozen dataclasses provide a way to achieve a similar effect.
  • The author acknowledges that frozen dataclasses can be more complicated to work with than mutable dataclasses, but argues that the benefits may outweigh the added complexity.
  • The author provides an example of a Bank Account dataclass to illustrate the concept of frozen dataclasses, suggesting that this is a common use case for immutable objects.
  • The author notes that frozen dataclasses can be useful for working with Pandas Series, which also have a similar concept of immutability.
  • The author suggests that using the "dataclasses.replace" function is a good way to modify frozen dataclasses, as it avoids the need to create a new object with all the same fields.
  • The author notes that while frozen dataclasses are not truly immutable, they provide a way to enforce a similar concept in Python.

Why and How to Write Frozen Dataclasses in Python

The difference between frozen and non-frozen dataclasses.

The philosophy behind the frozen classes is pretty interesting.

We will start with an example of a normal, non-frozen, dataclass in Python that represents a Bank Account. Then we will transform it into a frozen class and discuss the difference.

A normal mutable Dataclass

So, we create a Bank Account so that we can add or block some amount. It is extremely simple and there is no need to explain it:

Now, we want to test it to be sure everything works fine:

And we can see that the tests are green:

============================= test session starts collected 2 items
test_normal.py ..                                                        [100%]
============================== 2 passed in 0.01s 

Transformation to a Frozen Dataclass

What can be simpler than this? Simply add the “frozen=True” to the decorator:

@dataclass(frozen=True)

and run the tests again. You will see this error:

E   dataclasses.FrozenInstanceError: cannot assign to field 'blocked'

The problem (or the feature) is that you may not change the fields of the Account object anymore.

But how do we change it then, for sure we want it to be changed at some point.

The idea is that the functions that mutate the object should now return new objects instead. If you have worked with Pandas Series before, then you may remember that any modifications return new objects instead of mutating. For example, let’s look at the reshape function:

a = a.reshape((2,3))

and not just:

a.reshape((2,3))

We apply the same principle: we do not change the object itself, but we return a similar but new object.

Let’s adjust the tests first.

Here we test that the new object is updated, and the old one stays the same, i.e. with the original amount.

Now, there are two ways to return a mutated object.

The first, the naive one, is to return an absolutely new object like this:

But if there are too many fields, we do not want to duplicate all fields all the time, so we use the “dataclasses.replace” function as follows:

Why?

Why should anyone write frozen classes? This only seems more complicated, doesn’t it?

The main reason for this is to make sure your objects are only modified using the functions. So, your objects are truly immutable.

Let’s try change the amount, for example:

PyCharm immediately reacts with an error. Even if you ignore this and run the test, you will get an error:

So if you have some strict logic and want to avoid any kind of object smodifications by simply changing the variables, then the frozen dataclasses should be your choice.

Is it truly immutable?

In Python, it’s more a philosophy behind immutability, private and protected variables etc. So, it’s more like “i would like these methods to be private”, but doesn’t make it impossible to really call a private method from outside.

Same here. You may still change the variables in the object by using something like this:

object.__setattr__(account, "amount", 20)

Liked it? Have a look at my other articles on Python and Django. For example, you may like this one:

More content at plainenglish.io. Sign up for our free weekly newsletter. Get exclusive access to writing opportunities and advice in our community Discord.

Python
Programming
Immutable
Data Science
Coding
Recommended from ReadMedium