Задать вопрос
@maltsevdm

Можно ли в Python сделать такой механизм, чтобы при изменении значения в любой ветки словаря, я был уведомлен?

Например, у меня есть словарь:
some_dict = {
    'x': 1,
    'y': 2,
    'z': {'three': 3, 'four': 4}
}


Мне нужно чтобы при изменении любого значения словаря, в том числе значения словаря по ключу 'z', выполнялся определенный код. На данный момент я знаю только способ через создание нового класса, наследующегося от dict, и переопределение в нём методов __init__, __setitem__, __getitem__. Но этот способ будет работать только если каждый вложенный словарь оборачивать в этот класс.

class MyDict(dict):
    def __init__(self, obj):
        print('Создан объект')
        super(MyDict, self).__init__(obj)

    def __setitem__(self, item, value):
        print(f"Вы поменяли значение {item} на {value}!")
        super(MyDict, self).__setitem__(item, value)

    def __getitem__(self, item):
        print(f"Пытаемся получить значение {item}")
        return super(MyDict, self).__getitem__(item)


Может быть существует какой-то другой способ, так как этот мне не очень подходит?
  • Вопрос задан
  • 197 просмотров
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 2
fenrir1121
@fenrir1121
Начни с документации
Наследование от dict повлечет за собой неявные ошибки, используйте предназначенный для этого collections.UserDict
from collections import UserDict
class MyDict(UserDict):
    def __setitem__(self, key, value):
        print(f'Меняем значение {key} на {value}')
        super().__setitem__(key, value)


Мне нужно чтобы при изменении любого значения словаря, в том числе значения словаря по ключу 'z', выполнялся определенный код.

Очевидно вам это нужно для ваших конкретных словарей с бизнес логикой. И это нормально что они будут отдельным классом. Питон под капотом тоже использует словари и там явно не должен выполняться ваш код.
Ответ написан
Комментировать
@twistfire92
Python backend developer
Как верно подметил fenrir , наследоваться надо от UserDict.
Чуть поменял код, можете посмотреть что вышло. Была еще проблема в том, что при создании объекта вызывается метод __setitem__, для этого добавил флаг _initialization_finished

from collections import UserDict


class MyDict(UserDict):
    def __init__(self, **kwargs):
        self._initialization_finished = False
        print('Создан объект')
        super().__init__(**kwargs)
        self._initialization_finished = True

    def __setitem__(self, item, value):
        if self._initialization_finished:
            print(f"Вы поменяли значение {item} на {value}!")
        if isinstance(value, dict):
            value = MyDict(**value)
        super().__setitem__(item, value)

    def __getitem__(self, item):
        print(f"Пытаемся получить значение {item}")
        return super().__getitem__(item)


d = MyDict(x='123', y=15, z={'a': 4})
# Создан объект
# Создан объект

d['x'] = '456'
# Вы поменяли значение x на 456!

e = d['y']
# Пытаемся получить значение y


Два сообщения подряд "Создан объект" из-за того, что сначала создается основной кастомный словарь, потом создается словарь под ключом z, который тоже вызывает сообщение
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы