@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)


Может быть существует какой-то другой способ, так как этот мне не очень подходит?
  • Вопрос задан
  • 195 просмотров
Пригласить эксперта
Ответы на вопрос 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, который тоже вызывает сообщение
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы
02 мая 2024, в 21:59
15000 руб./за проект
02 мая 2024, в 21:54
1000 руб./в час
02 мая 2024, в 21:27
300000 руб./за проект