Переопределение метода dict.update () в подклассе для предотвращения перезаписи ключей dict
Ранее сегодня я прочитал вопросПоднимите ошибку, если python в понимании dict перезаписывает ключ"и решил попробовать свои силы в ответ. Метод, который естественным образом мне пришло в голову, состоял в том, чтобы подклассdict
за это. Тем не менее, я застрял в своем ответе, и теперь я одержим тем, чтобы это сработало для себя.
Заметки:
Нет - я не планирую превращать ответ на этот вопрос в ответ на другой вопрос.На данный момент это чисто интеллектуальное упражнение для меня. На практике я почти наверняка использовал быnamedtuple
или обычный словарь, где у меня есть требование для чего-то вроде этого.Мое (не совсем рабочее) решение:class DuplicateKeyError(KeyError):
pass
class UniqueKeyDict(dict):
def __init__(self, *args, **kwargs):
self.update(*args, **kwargs)
def __setitem__(self, key, value):
if key in self: # Validate key doesn't already exist.
raise DuplicateKeyError('Key \'{}\' already exists with value \'{}\'.'.format(key, self[key]))
super().__setitem__(key, value)
def update(self, *args, **kwargs):
if args:
if len(args) > 1:
raise TypeError('Update expected at most 1 arg. Got {}.'.format(len(args)))
else:
try:
for k, v in args[0]:
self.__setitem__(k, v)
except ValueError:
pass
for k in kwargs:
self.__setitem__(k, kwargs[k])
Мои тесты и ожидаемые результаты>>> ukd = UniqueKeyDict((k, int(v)) for k, v in ('a1', 'b2', 'c3', 'd4')) # Should succeed.
>>> ukd['e'] = 5 # Should succeed.
>>> print(ukd)
{'a': 1, 'b': 2, 'c': 3, d: 4, 'e': 5}
>>> ukd['a'] = 5 # Should fail.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __setitem__
__main__.DuplicateKeyError: Key 'a' already exists with value '1'.
>>> ukd.update({'a': 5}) # Should fail.
>>> ukd = UniqueKeyDict((k, v) for k, v in ('a1', 'b2', 'c3', 'd4', 'a5')) # Should fail.
>>>
Я уверен, что проблема в моемupdate()
метод, но я не могу определить, что я делаю неправильно.
Ниже оригинальная версия моегоupdate()
метод. Эта версия дает сбой, как и ожидалось на дубликатах при вызовеmy_dict.update({k: v})
для пары ключ / значение, уже имеющейся в dict, но не завершается ошибкой при добавлении дубликата ключа при создании исходного dict из-за того, что преобразование аргументов вdict
приводит к поведению по умолчанию для словаря, т.е. перезаписывает дубликат ключа.
def update(self, *args, **kwargs):
for k, v in dict(*args, **kwargs).items():
self.__setitem__(k, v)