2015-08-27 64 views
4

創建密鑰假設我有d = {'dogs': 3}。使用:如何防止通過d [key] = val

d['cats'] = 2 

將創建密鑰'cats',並給它的價值2

如果我真的打算用新的密鑰和值更新字典,我會使用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 

問:
有沒有一種方法來禁用自動創建一個關鍵的這不存在通過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 
+1

我想你可以繼承' dict'併爲相關的魔術方法編寫自定義函數。 – TigerhawkT3

+1

看看這個http://stackoverflow.com/questions/2390827/how-to-properly-subclass-dict-and-override-getitem-setitem – ballsatballsdotballs

+0

你已經自相矛盾。你爲什麼不用'd.update(狗= 1)'就像你說的那樣? – chepner

回答

3

您可以創建的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 

這不是完全防彈(例如,它會允許x.update({"cats": 99})沒有投訴),但它可以防止最有可能的情況。

+1

這是否打破了所有其他的字典魔法? –

+2

@JoranBeasley它不應該,因爲它繼承了,所有其他的魔法方法都會留下來。 –

+0

啊這似乎是你的權利......我發誓我用字符串做了這件事,它打破了我沒有明確子類的所有魔術方法...也許它只是因爲字符串比字典或其他東西更原始 –

0

繼承dict類並覆蓋__setitem__到適合你的needs.Try這

class mydict(dict): 
    def __init__(self, *args, **kwargs): 
     self.update(*args, **kwargs) 
    def __setitem__(self, key, value): 
     raise KeyError(key) 

>>>a=mydict({'a':3}) 
>>>d 
{'a': 3} 
>>>d['a'] 
3 
>>>d['b']=4 
KeyError: 'b' 
0

這將只允許使用更新key=value添加新鍵:

class MyDict(dict): 
    def __init__(self, d): 
     dict.__init__(self) 
     self.instant = False 
     self.update(d) 

    def update(self, other=None, **kwargs): 
     if other is not None: 
      if isinstance(other, dict): 
       for k, v in other.items(): 
        self[k] = v 
      else: 
       for k, v in other: 
        self[k] = v 
     else: 
      dict.update(self, kwargs) 
     self.instant = True 

    def __setitem__(self, key, value): 
     if self.instant and key not in self: 
      raise KeyError(key) 
     dict.__setitem__(self, key, value) 

x = MyDict({1:2,2:3}) 
x[1] = 100 # works 
x.update(cat=1) # works 
x.update({2:200}) # works 
x["bar"] = 3 # error 
x.update({"foo":2}) # error 
x.update([(5,2),(3,4)]) # error