python - Overriding dict.update() method in subclass to prevent overwriting dict keys -
earlier today, read question "raise error if python dict comprehension overwrites key" , decided try hand @ answer. method naturally occurred me subclass dict this. however, got stuck on answer, , i'm obsessed getting worked out myself.
notes:
- no - not plan on turning in answer question answer other question.
- this purely intellectual exercise me @ point. practical matter, use
namedtupleor regular dictionary wherever have requirement this.
my (not quite working) solution:
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 exist. raise duplicatekeyerror('key \'{}\' exists value \'{}\'.'.format(key, self[key])) super().__setitem__(key, value) def update(self, *args, **kwargs): if args: if len(args) > 1: raise typeerror('update expected @ 1 arg. got {}.'.format(len(args))) else: try: k, v in args[0]: self.__setitem__(k, v) except valueerror: pass k in kwargs: self.__setitem__(k, kwargs[k]) my tests , expected results
>>> ukd = uniquekeydict((k, int(v)) 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' exists value '1'. >>> ukd.update({'a': 5}) # should fail. >>> ukd = uniquekeydict((k, v) k, v in ('a1', 'b2', 'c3', 'd4', 'a5')) # should fail. >>> i'm issue in update() method, i'm not able determine i'm doing wrong.
below original version of update() method. version fails expected on duplicates when calling my_dict.update({k: v}) key/value pair in dict, not fail when including duplicate key while creating original dict, due fact converting args dict results in default behavior dictionary, i.e., overwriting duplicate key.
def update(self, *args, **kwargs): k, v in dict(*args, **kwargs).items(): self.__setitem__(k, v)
note that, per documentation:
dict.updatetakes singleotherparameter, "either dictionary object or iterable of key/value pairs" (i've usedcollections.mappingtest this) , "if keyword arguments specified, dictionary updated key/value pairs"; anddict()takes singlemappingoriterablealong optional**kwargs(the sameupdateaccepts...).
this not quite interface have implemented, leading issues. have implemented follows:
from collections import mapping class duplicatekeyerror(keyerror): pass class uniquekeydict(dict): def __init__(self, other=none, **kwargs): super().__init__() self.update(other, **kwargs) def __setitem__(self, key, value): if key in self: msg = 'key {!r} exists value {!r}' raise duplicatekeyerror(msg.format(key, self[key])) super().__setitem__(key, value) def update(self, other=none, **kwargs): if other not none: k, v in other.items() if isinstance(other, mapping) else other: self[k] = v k, v in kwargs.items(): self[k] = v in use:
>>> uniquekeydict((k, v) k, v in ('a1', 'b2', 'c3', 'd4')) {'c': '3', 'd': '4', 'a': '1', 'b': '2'} >>> uniquekeydict((k, v) k, v in ('a1', 'b2', 'c3', 'a4')) traceback (most recent call last): file "<pyshell#8>", line 1, in <module> uniquekeydict((k, v) k, v in ('a1', 'b2', 'c3', 'a4')) file "<pyshell#7>", line 5, in __init__ self.update(other, **kwargs) file "<pyshell#7>", line 15, in update self[k] = v file "<pyshell#7>", line 10, in __setitem__ raise duplicatekeyerror(msg.format(key, self[key])) duplicatekeyerror: "key 'a' exists value '1'" and:
>>> ukd = uniquekeydict((k, v) k, v in ('a1', 'b2', 'c3', 'd4')) >>> ukd.update((k, v) k, v in ('e5', 'f6')) # single iterable >>> ukd.update({'h': 8}, g='7') # single mapping plus keyword args >>> ukd {'e': '5', 'f': '6', 'a': '1', 'd': '4', 'c': '3', 'h': 8, 'b': '2', 'g': '7'} if ever end using this, i'd inclined give different __repr__ avoid confusion!
Comments
Post a Comment