TL; доктор
Подкласс коллекции. Userdict
, не Дикт
Отказ
Дольше описание
Мне нужна словарь, подобная переменную, и пропустите ее к другой функции, когда функция возвращается, мне нужно знать, был ли этот словарь изменен (ключ или значение), если оно есть, я сделаю сохранение базы данных (если Видя это как процесс спасения сеансов на стороне сервера, это именно). Поскольку это частое операция, я хочу сделать это как можно быстрее.
Первая идея пришла на мой взгляд, как это:
session_dict = {} old_dict = {**session_dict} # now call function func(session_dict) if session_dict != old_dict: # change happend, do database saving
Но этот метод требует копии словаря, которая стоила больше места и сравнивайте два объекта словаря, я уверен, что внутри появилось некоторое рекурсивное сравнение, которое может стоить больше времени.
Вторая идея использует Парил
Для сравнения маринованной строки:
import pickle session_dict = {} finger_print = pickle.dumps(session_dict) func(session_dict) if pickle.dumps(session_dict) == finger_print: # change happend, do database saving
Это использует Pickle.dumps
Чтобы преобразовать словарь в строку, затем после вызова функции он сравнивает строку. На основании того, как долго строка, это может стоить больше времени процессора.
Третья идея – подкласс Дикт
, а когда __setitem__
и __delitem__
называются, отметьте флаг изменения (вы также можете увидеть мой предыдущий пост здесь на подклассном дикторе В Python для поддержки доступа точечного синтаксиса):
class ChangeDetectableDict(dict): def __init__(self, val=None): if val is None: val = {} super().__init__(val) self.changed = False def __setitem__(self, item, value): super().__setitem__(item, value) self.changed = True def __delitem__(self, item): super().__delitem__(item) self.changed = True
Это отлично работает, если у нас есть код, чтобы установить ключ:
session_dict = ChangeDetectableDict() session_dict["name"] = "bo" print(session_dict.changed) # True
Или удалить ключ:
session_dict = ChangeDetectableDict({"name": "bo"}) del session_dict["name"] print(session_dict.changed) # True
Это сделает обнаружение изменений во времени O (1)
, что отлично. Но вы можете увидеть проблему, что если я установлю значение ключа, чтобы быть одинаковым значением, изменился
все еще будет помечено как True:
session_dict = ChangeDetectableDict({"name": "bo"}) session_dict["name"] = "bo"] print(session_dict.changed) # True
В моем случае я в порядке с этим, пока что-то изменилось, изменился
Будет отмечен как True, я не против, чтобы иметь несколько ложных положительных случаев. Но настоящая проблема в том, что если я не пользуюсь дель
Чтобы удалить ключ, использовать поп
вместо этого __delitem__
Метод не будет вызван, таким образом изменился
все еще ложно:
session_dict = ChangeDetectableDict({"name": "bo"}) session_dict.pop("name", None) print(session_dict.changed) # False
Это недопустимо для моего случая использования, и причина, по которой это происходит, это потому, что встроенный Python Дикт
имеет некоторые встроенные оптимизации, которые ведут поп
не звонить __delitem__
Отказ
Итак, четвертый метод, который я нашел, не подклассно обдумывать
вместо этого подкласс коллекции. Userdict
:
from collections import UserDict class ChangeDetectableDict(UserDict): def __init__(self, val=None): if val is None: val = {} super().__init__(val) self.changed = False def __setitem__(self, item, value): super().__setitem__(item, value) self.changed = True def __delitem__(self, item): super().__delitem__(item) self.changed = True
Теперь независимо от того, мы не используем дель
или поп
, __delitem__
Метод всегда будет вызывать Таким образом, отметьте изменился
быть правдой.
Вернуться к началу, теперь я могу написать код так:
session_dict = ChangeDetectableDict() func(session_dict) if session_dict.changed: # change happend, do database saving
Оригинал: “https://dev.to/0xbf/customize-your-own-dictionary-python-tips-5b47”