While reading into implementing DDD, there is often a plea for the use of immutable objects. The main motivation is that an object that is initially valid always remains valid; there is no later verification or validation required. Secondly, working with an immutable object cannot cause any side effects.

Some data objects in Python are immutable, the dataclasses themselve are not. Let’s have this simple class:

class SimpleClass:
    def __init__(self, attr1: int):
        self.attr1 = attr1

With this setup, you can change any of its attributes making the object not immutable:

>> my_object = SimpleClass(attr1=1)
>> my_object.attr1 = 2  # this is a mutable object
>> my_object.attr2 = 4  # again, this is a mutable object
>> my_object.__dict__
{'attr1': 2, 'attr2': 4}

Frozen instances

The solution is simple: if you are on Python 3.7+, you can use a Data Class with frozen instances, which is just a decorator:

from dataclasses import dataclass

@dataclass(frozen=True)
class MyImmutableClass:

    attr1: int

Changing the attributes now fails:

>> immutable_obj = MyImmutableClass(attr1=1)
>> immutable_obj.attr1 = 2
FrozenInstanceError: cannot assign to field 'attr1'

Just as adding any attribute:

>> immutable_obj.attr2 = 3
FrozenInstanceError: cannot assign to field 'attr2'
>> immutable_obj.__dict__
{'attr1': 1}

Thanks to Jundiaius on SO.