Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent key creation through d[key] = val

Suppose I have d = {'dogs': 3}. Using:

d['cats'] = 2 

would create the key 'cats' and give it the value 2.

If I really intend to update a dict with a new key and value, I would use d.update(cats=2) because it feels more explicit.

Having automatic creation of a key feels error prone (especially in larger programs), e.g.:

# I decide to make a change to my dict.
d = {'puppies': 4, 'big_dogs': 2}


# Lots and lots of code.
# ....

def change_my_dogs_to_maximum_room_capacity():
    # But I forgot to change this as well and there is no error to inform me.
    # Instead a bug was created.
    d['dogs'] = 1

Question:
Is there a way to disable the automatic creation of a key that doesn't exist through d[key] = value, and instead raise a KeyError?

Everything else should keep working though:

d = new_dict()                  # Works
d = new_dict(hi=1)              # Works
d.update(c=5, x=2)              # Works
d.setdefault('9', 'something')  # Works

d['a_new_key'] = 1              # Raises KeyError
like image 775
user Avatar asked Aug 27 '15 20:08

user


Video Answer


1 Answers

You could create a child of dict with a special __setitem__ method that refuses keys that didn't exist when it was initially created:

class StrictDict(dict):
    def __setitem__(self, key, value):
        if key not in self:
            raise KeyError("{} is not a legal key of this StricDict".format(repr(key)))
        dict.__setitem__(self, key, value)

x = StrictDict({'puppies': 4, 'big_dogs': 2})
x["puppies"] = 23 #this works
x["dogs"] = 42    #this raises an exception

It's not totally bulletproof (it will allow x.update({"cats": 99}) without complaint, for example), but it prevents the most likely case.

like image 129
Kevin Avatar answered Sep 30 '22 13:09

Kevin