Ранее сегодня я прочитал вопрос "Повысить ошибку, если понимание 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 из-за того, что преобразование args в dict
приводит к поведению по умолчанию для словаря, то есть перезаписыванию дубликата ключа.
def update(self, *args, **kwargs):
for k, v in dict(*args, **kwargs).items():
self.__setitem__(k, v)