如何通过d [key] = val来防止密钥创建

Fer*_*dox 5 python dictionary key python-3.4

假设我有d = {'dogs': 3}.使用:

d['cats'] = 2 
Run Code Online (Sandbox Code Playgroud)

会创建密钥'cats'并赋予它价值2.

如果我真的打算用新的键和值来更新dict,我会使用d.update(cats=2)它,因为它感觉更明确.

自动创建密钥会感觉容易出错(特别是在较大的程序中),例如:

# 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
Run Code Online (Sandbox Code Playgroud)

问题:
有没有办法禁用自动创建不存在的密钥,d[key] = value而是提出一个KeyError

其他一切应该继续工作:

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
Run Code Online (Sandbox Code Playgroud)

Kev*_*vin 5

您可以dict使用特殊__setitem__方法创建的子项,该方法拒绝最初创建键时不存在的键:

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
Run Code Online (Sandbox Code Playgroud)

它不是完全防弹的(x.update({"cats": 99})例如,可以毫无怨言地允许),但是它可以防止最可能的情况发生。

  • @JoranBeasley它不应该™,因为它继承了,所以所有其他魔术方法都会存在。 (2认同)