2011-02-15 39 views
6

如果用戶在字典中輸入重複鍵,則會嘗試引發錯誤。字典在文件中,用戶可以手動編輯文件。如果在字典中重複鍵時出現錯誤

例子:

dico= {'root':{ 
       'a':{'some_key':'value',...}, 
       'b':{'some_key':'value',...}, 
       'c':{'some_key':'value',...}, 
       ... 

       'a':{'some_key':'value',...}, 
       } 
     } 

新密鑰「A」已經存在......

如何我可以測試迪科和提醒用戶,當我從文件加載迪科?

+0

你是如何從文件加載字典? – 2011-02-15 01:59:27

+1

@HughBothwell:用`from x import dico` – Thammas 2011-02-15 02:35:12

回答

12

編寫dict的子類,覆蓋__setitem__,以便在替換現有密鑰時引發錯誤;重寫該文件以使用新的子類的構造函數而不是默認的dict內置函數。

import collections 

class Dict(dict): 
    def __init__(self, inp=None): 
     if isinstance(inp,dict): 
      super(Dict,self).__init__(inp) 
     else: 
      super(Dict,self).__init__() 
      if isinstance(inp, (collections.Mapping, collections.Iterable)): 
       si = self.__setitem__ 
       for k,v in inp: 
        si(k,v) 

    def __setitem__(self, k, v): 
     try: 
      self.__getitem__(k) 
      raise ValueError("duplicate key '{0}' found".format(k)) 
     except KeyError: 
      super(Dict,self).__setitem__(k,v) 

那麼你的文件將有被寫成使用的,而不是對文件導入類型的字典(使用{}符號寫成的元組

dico = Dict(
    ('root', Dict(
     ('a', Dict(
      ('some_key', 'value'), 
      ('another_key', 'another_value') 
     ), 
     ('b', Dict(
      ('some_key', 'value') 
     ), 
     ('c', Dict(
      ('some_key', 'value'), 
      ('another_key', 'another_value') 
     ), 

     .... 
    ) 
) 

,它會使用默認的字典構造函數和在Dict構造函數獲得它們之前,重複項會消失!)。

+0

這是最好的解決方案!它不僅在您嘗試逐個添加項目時,而且在將具有重複第一項的元組列表轉換爲字典時引發預期異常:Dict([(1,2),(3,4),( 1,6)])。 – jciloa 2016-06-29 17:50:28

1

Python的默認行爲是在聲明字典時默默覆蓋重複項。

您可以創建自己的字典類,在添加新元素之前檢查項目是否已存在於字典中,然後使用它。但是,那麼您將不得不將該文件中的dico聲明更改爲允許重複的內容,例如元組列表。

然後在加載該數據文件時,將其解析爲您特殊的'subclassed'字典。

4

如果密鑰已存在,您將需要定製字典,該字典可以用ValueError拒絕。

class RejectingDict(dict): 
    def __setitem__(self, k, v): 
     if k in self.keys(): 
      raise ValueError("Key is already present") 
     else: 
      return super(RejectingDict, self).__setitem__(k, v) 

這是它是如何工作的。

>>> obj = RejectingDict() 
>>> obj[1] = True 
>>> obj[2] = False 
>>> obj 
{1: True, 2: False} 
>>> obj[1] = False 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "rejectingdict.py", line 4, in __setitem__ 
    raise ValueError("Key is already present") 
ValueError: Key is already present 
+1

請注意,self.keys()中的k是O(n),您應該直接使用`in self`(未檢查) – iggy 2015-07-02 15:36:38

3

錯誤的方式
GO BACK

from x import dico是不是一個很好的主意 - 你是讓用戶編輯代碼,然後您可以執行盲目。你冒着簡單的拼寫錯誤導致語法錯誤的風險,直到import os; os.system("rm whatever"); dico = {}等惡意東西。

不要繼續與子類dict。寫你自己的字典裝載機。這並不難......讀取數據文件,在每次插入之前檢查密鑰是否已存在;如果確實如此,請使用行號和重複鍵及其值等有意義的內容記錄錯誤消息。最後,如果出現任何錯誤,請舉例說明。您可能會發現現有的模塊可以完成所有這些...... Python提供的ConfigParser aka configparser似乎並不是您想要的。

順便說一句,在頂層沒有一個'根'鍵而沒有意義?

1

如果你想確保在dict建設有重複鍵,只是利用Python的native關鍵字參數檢查將引發錯誤:

> dict(a={}, a={}) 
SyntaxError: keyword argument repeated 

除非我失去了一些東西,就沒有必要繼承dict