0

I want to add elements (key-value-pairs) to a dict. But I want to prevent overwriting existing values when the key exists.

But I don't want to do an if check. I would prefer an exception.

d = {}

d['a'] = 1
d['b'] = 2
d['a'] = 3  # <-- raise Exception! "KeyExistsException'

What I don't want

if not 'a' in d:
    d['a'] = 3
buhtz
  • 10,774
  • 18
  • 76
  • 149
  • You could implement your own custom dict class to do this. You'll still need the `if key in dict` check, but it can be written once, inside the class. – John Gordon Jul 27 '22 at 19:25
  • 1
    One option if you are on Python 3.9 or higher: `d = {'a': 3} | d`. This will update the dictionary, but conflicting keys will always use the existing values from `d`. – 0x5453 Jul 27 '22 at 19:25
  • But there is no exception. – buhtz Jul 27 '22 at 19:27
  • Ahh, right. There is no built-in way to do that - you'll either need a manual `if` check or a custom `dict` class that has your desired behavior. – 0x5453 Jul 27 '22 at 19:29
  • 1
    why do you prefer the exception? – juanpa.arrivillaga Jul 27 '22 at 19:32
  • This may help. [How to raise error if duplicates keys in dictionary](https://stackoverflow.com/questions/4999233/how-to-raise-error-if-duplicates-keys-in-dictionary) – Nesi Jul 27 '22 at 19:36
  • It doesn't raise an exception, but if you use the `setdefault` dict method to add key-value pairs, it won't overwrite existing key values, e.g., `d.setdefault("a", 3)` – Matt Pitkin Jul 27 '22 at 19:38
  • 1
    @0x5453 since you are already using a literal, I think `d = {"a":3, **d}` would be nicer. But both of these approache would be inefficient (linear time) so they shouldn't be used if this needs to happen repeatedly. But more idiomatically, i would just use `d.setdefault("a", 3)` – juanpa.arrivillaga Jul 27 '22 at 19:40

3 Answers3

2

You can subclass dict and in particular, override the __setitem__ method.

This sounds like what you want:

class SpecialDict(dict):
    def __setitem__(self, key, value):
        if not key in self:
            super(SpecialDict, self).__setitem__(key, value)
        else:
            raise Exception("Cannot overwrite key!") # You can make your own type here if needed


x = SpecialDict()


x['a'] = 1
x['b'] = 2
x['a'] = 3  #raises Exception
JacobIRR
  • 8,545
  • 8
  • 39
  • 68
1

Instead of subclassing dict as suggested by JacobIRR, you could also define a helper function for storing a key-value pair in a dict that throws an exception when the key already exists:

class KeyExistsException(Exception):
    pass

def my_add(the_dict, the_key, the_value):
    if the_key in the_dict:
        raise KeyExistsException("value already exists")
    the_dict[the_key] = the_value


d = {}

my_add(d, 'a', 1)
my_add(d, 'b', 2)
my_add(d, 'a', 3)  # <-- raise Exception! "KeyExistsException'
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
jboockmann
  • 1,011
  • 2
  • 11
  • 27
1

This might work for your use. I am a noob so I may be overlooking something.

d = {}
 
try:
    d['new_key']  # check if key exists.
except KeyError:  # if not exist create.
    d['new_key'] = 'value'
else:  # else raise exception KeyExists.
    raise Exception ('KeyExists')
Nesi
  • 286
  • 2
  • 15