Разница между замороженными и незамороженными классами данных.

Философия замороженных классов довольно интересна.

Мы начнем с примера обычного незамороженного класса данных в Python, представляющего собой банковский счет. Затем мы превратим его в замороженный класс и обсудим разницу.

Обычный изменяемый класс данных

Итак, мы создаем банковский счет, чтобы мы могли добавить или заблокировать некоторую сумму. Это очень просто и объяснять не нужно:

Теперь мы хотим протестировать его, чтобы убедиться, что все работает нормально:

И мы видим, что тесты зеленые:

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

Преобразование в замороженный класс данных

Что может быть проще этого? Просто добавьте в декоратор «frozen=True»:

@dataclass(frozen=True)

и снова запустить тесты. Вы увидите эту ошибку:

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

Проблема (или особенность) заключается в том, что вы больше не можете изменять поля объекта Account.

Но как мы его потом изменим, ведь мы точно хотим, чтобы он когда-то изменился.

Идея состоит в том, что функции, изменяющие объект, теперь должны вместо этого возвращать новые объекты. Если вы раньше работали с Pandas Series, то, возможно, помните, что любые модификации возвращают новые объекты, а не мутируют. Например, давайте посмотрим на функцию изменения формы:

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

и не только:

a.reshape((2,3))

Применяем тот же принцип: не меняем сам объект, а возвращаем аналогичный, но новый объект.

Сначала настроим тесты.

Здесь мы проверяем, что новый объект обновляется, а старый остается прежним, т.е. с исходной суммой.

Теперь есть два способа вернуть измененный объект.

Первый, наивный, — вернуть абсолютно новый объект, например:

Но если полей слишком много, мы не хотим все время дублировать все поля, поэтому используем функцию «dataclasses.replace» следующим образом:

Почему?

Почему кто-то должен писать замороженные классы? Это только кажется более сложным, не так ли?

Основная причина этого заключается в том, чтобы убедиться, что ваши объекты изменяются только с помощью функций. Итак, ваши объекты действительно неизменны.

Попробуем изменить сумму, например:

PyCharm сразу реагирует ошибкой. Даже если вы проигнорируете это и запустите тест, вы получите ошибку:

Поэтому, если у вас есть строгая логика и вы хотите избежать каких-либо модификаций объектов, просто изменив переменные, тогда вам следует выбрать замороженные классы данных.

Действительно ли оно неизменно?

В Python это скорее философия неизменяемости, приватных и защищенных переменных и т. д. Таким образом, это больше похоже на «я бы хотел, чтобы эти методы были приватными», но не делает невозможным вызов приватного метода извне.

То же самое. Вы все еще можете изменить переменные в объекте, используя что-то вроде этого:

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

Понравилось это? Посмотрите другие мои статьи о Python и Django. Например, вам может понравиться вот это:



Больше контента на plainenglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Получите эксклюзивный доступ к возможностям написания и советам в нашем сообществе Discord.