Сделать Dataclass объект immutable после __post_init__

Есть класс

from typing import List
from dataclasses import dataclass, field

@dataclass(repr=False, eq=False, order=False)
class Models:
    path: str 
    targets: List[str] = field(default_factory=list) 
    columns: List[str] = field(default_factory=list, init=False)

Атрибут columns я определяю в __ post_init __(self)

def __post_init__(self):
    self.columns = ['a', 'b', 'c']

И мне бы хотелось сделать объект класса Models immutable после инициализации (пост-инициализации?)

Если прописать @dataclass(Frozen=True) , то теряется возможность определить атрибут в post_init

Можно ли прописать аналог Frozen=True, только уже после init и post_init?

Какие могут быть альтернативные варианты?


Ответы (1 шт):

Автор решения: gil9red

Можно переопределить магический метод __setattr__ и в нем выбрасывать исключение.

Пример:

from typing import List
from dataclasses import dataclass, field

@dataclass(repr=False, eq=False, order=False)
class Models:
    path: str
    targets: List[str] = field(default_factory=list)
    columns: List[str] = field(default_factory=list, init=False)

    def __post_init__(self):
        self.columns = ['a', 'b', 'c']

        self._is_post_init = True

    def __setattr__(self, key, value):
        if hasattr(self, '_is_post_init'):
            raise Exception(f'cannot assign to field "{key}"')
        return super().__setattr__(key, value)

Models('123').columns = []
# Exception: cannot assign to field "columns"
→ Ссылка