2011-02-15 86 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