我不是故意的,因为标准是这样说的,但是它的基本原理。规范说:
如果给出了逗号分隔的键/数据对序列,则从左到右计算它们以定义字典的条目:每个键对象用作字典中的键以存储相应的数据。这意味着您可以在键/基准列表中多次指定相同的键,并且该键的最终字典值将是给定的最后一个。
这意味着通过以下方式形成dict
是完全合法的:
d = { 'a': 1, 'b':2, 'b':3 }
但是我几乎没有理由为什么要这样定义它,通常我猜这是一个错误。如果将关键字参数与函数进行比较,则禁止使用相应的构造。
有没有一种避免这种情况的好方法?
答案 0 :(得分:3)
此“错误”已被报告,讨论并最终被拒绝 - 请参阅https://bugs.python.org/issue16385。
拒绝者指定的主要原因是
代码生成器可能依赖于能够编写重复键而无需返回并擦除先前的输出。
那个
出于兼容性原因,错误无法解决。
答案 1 :(得分: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)))
答案 2 :(得分: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
。