2017-01-23 86 views
1

我的意思并不是因为标准这么说,而是它的理由。规范说:为什么`dict_display`允许重复键?

如果给出了一个以逗号分隔的键/数据对序列,则会从左到右评估它们以定义词典的条目:每个键对象都用作字典中的键存储相应的数据。这意味着您可以在键/数据列表中多次指定相同的键,并且该键的最终字典值将是最后给出的值。

这意味着它是完全合法的形成dict通过:

d = { 'a': 1, 'b':2, 'b':3 } 

不过,我几乎看不到,为什么一个想定义它的方式任何理由,最常见的我想这是一个错误。如果您将关键字参数与函数进行比较,则相应的结构将被禁止。

有没有避免这种情况的好方法?

回答

3

此“bug”已被报告,讨论并最终被拒绝 - 请参阅https://bugs.python.org/issue16385

由rejectors指定的主要理由是

代码生成器可以依赖于能够写出重复键,而不必回去和擦除以前的输出。

错误是出于兼容性的原因的问题。

2

我发现this discussion,这引起了这一点:

d = {spam(a): 'a', spam(b): 'BB', spam(c): 'Ccc'} 

这不仅凸显,这必须是一个运行时的事情,但也有情况下,您可能要允许它。例如,当正在生成的代码,或字典内涵,其覆盖默认值等

defaults = {'a': 1, 'b': 2} 
specific = {'b': 3, 'c': 4} 
combined = {key: val for key, val in itertools.chain(defaults.items(), specific.items())} 

作为我个人而言,它也与.update非常适合,它增加或更新的关键,而不是抱怨的时候它已经存在。

作为一种方法来防止这种情况,当密钥是有效的Python的关键字,你可以使用:

d = dict(a=1, b=2, b=3) 

你当然也可以让自己的包装,但它会很难看:

def uniqdict(items): 
    dct = {} 
    for key, val in items: 
     if key in dct: 
      raise KeyError('key {0:} already exists'.format(key)) 
     dct[key] = val 
    return dct 

uniqdict((('a', 1), ('b', 2), ('b', 3))) 
1

至少有几种情况下,您可能会使用dict接受多个相同密钥的行为,因为dictionary display is now evaluated left to right

1)如果多个键评估为相同的输出,但您只想采用最后一个实例。

例如,假设你想显示一个数字,如果它是偶数或“奇数”;你可以使用字典:

def f(n): 
    return {True: n, n % 2: 'odd'}[True] 

当然,这个例子有更多可读的方法,比如使用if-else子句,但它说明了这一点。

2)使用OrderedDict,利用此行为是推荐的方法,可以在保留订单的同时从列表中删除重复项,如Raymond Hettinger says。例如:

from collections import OrderedDict 
list(OrderedDict.fromkeys(['a','b','d','d','a'])) 
# ['a', 'b', 'd'] 

如果您担心的行为,你应该简单地检查你的密钥建立字典,例如assert len(keys) == len(set(keys))之前唯一的。你可以在添加它之前检查关键字是否在字典中,if key not in my_dict: my_dict[key] = value