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 namedtuple or 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.update takes single other parameter, "either dictionary object or iterable of key/value pairs" (i've used collections.mapping test this) , "if keyword arguments specified, dictionary updated key/value pairs"; and
  • dict() takes single mapping or iterable along optional **kwargs (the same update accepts...).

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

Popular posts from this blog

Email notification in google apps script -

c++ - Difference between pre and post decrement in recursive function argument -

javascript - IE11 incompatibility with jQuery's 'readonly'? -