【问题标题】:Python update a key in dict if it doesn't exist如果 dict 中的键不存在,Python 会更新它
【发布时间】:2017-07-07 23:47:55
【问题描述】:

如果键不在 dict.keys() 中,我想在 dict 中插入一个键值对。 基本上我可以这样做:

if key not in d.keys():
    d[key] = value

但是有更好的方法吗?或者这个问题的pythonic解决方案是什么?

【问题讨论】:

标签: python dictionary


【解决方案1】:

你不需要打电话给d.keys(),所以

if key not in d:
    d[key] = value

就够了。没有比这更清晰、更易读的方法了。

您可以使用dict.get() 再次更新,如果密钥已经存在,它将返回一个现有值:

d[key] = d.get(key, value)

但我强烈建议不要这样做;这是代码打高尔夫球,妨碍维护和可读性。

【讨论】:

  • 如果我有多个线程使用代码,是否需要同步?
  • @ed22 是的,因为它由多个字节码指令组成,线程可以在它们之间切换。
  • 这个想法实用吗?尝试:dict[key] += 1 除外 KeyError:dict[key] = 1
  • @hatahetahmad:当然,但那是 4 行,而不是 2 行。
  • 我正在考虑复杂性,表达式“for k in keys run in O(k)”,另一方面“尝试,除了只需要 O(1)”。如果我错了,请纠正我;谢谢。
【解决方案2】:

使用dict.setdefault():

>>> d = {'key1': 'one'}
>>> d.setdefault('key1', 'some-unused-value')
'one'
>>> d    # d has not changed because the key already existed
{'key1': 'one'}
>>> d.setdefault('key2', 'two')
'two'
>>> d
{'key1': 'one', 'key2': 'two'}

【讨论】:

  • dict.setdefault() 应该只在尝试访问该值时使用。
  • @MartijnPieters:这有什么关系? setdefault() 这个名字清楚地描述了正在发生的事情——它也返回一个值并不是那么重要,而且有点古怪的 IMO。您能否提供一个快速解释或链接,说明为什么这是不可取的?
  • 您可以在期望值存在的表达式中使用它,例如在分组循环中:for obj in iterable: d.setdefault(key_for_obj(obj), []).append(obj)。返回的值没有什么奇怪的,这就是方法的重点
  • 此外,它会掩盖您正在尝试做的事情,即仅在密钥不存在时才设置密钥。可读性很重要,只需使用if key not in d: 测试。
  • @MartijnPieters:感谢您的解释。阅读文档字符串后,setdefault() 似乎确实适合您所说的内容。使用 defaultdict(list) 会产生比您的示例更具可读性的代码......所以除非必须使用标准字典,否则它可能没有用处。总的来说,if key not in d 更清晰。
【解决方案3】:

Python 3.9 开始,您可以使用 合并运算符 | 合并两个字典。右边的dict优先:

new_dict = old_dict | { key: val }

例如:

new_dict = { 'a': 1, 'b': 2 } | { 'b': 42 }

print(new_dict) # {'a': 1, 'b': 42}

注意:这会创建一个包含更新值的新字典。

【讨论】:

  • 虽然这很有趣,但我认为它并不比公认的答案更具可读性
  • 对我来说,很高兴知道现在有一种方法可以合并两个字典
  • 此合并存在挑战。如果键相同,则合并将忽略该值。如果这就是意图,那么它会起作用。
  • @JoeFerndz 右边的 dict 优先,不会忽略该值。我更新了示例以使这一点更清楚。
  • 问题是询问如何“更新字典中的键如果它不存在”,因此所需的输出将是字典保持不变{ 'a': 1, 'b': 2 }因为'b' in old_dict 已经。所以你必须把其他字典放在第一位{ key: val } | old_dict
【解决方案4】:

通过以下内容,您可以插入多个值并具有默认值,但您正在创建一个新字典。

d = {**{ key: value }, **default_values}

我用投票最多的答案对其进行了测试,平均而言这更快,如下例所示。

速度测试比较基于 for 循环的方法与带有解包运算符方法的 dict 理解。

如果在第一种情况下没有复制 (d = default_vals.copy()),那么一旦我们达到 10**5 或更大的数量级,投票最多的答案会更快。两种方法的内存占用是一样的。

【讨论】:

  • 那为什么首先建议它
  • 非常感谢。不过好像应该是{**default_values, **{ key: value }}
猜你喜欢
  • 2019-11-07
  • 2011-01-16
  • 1970-01-01
  • 2018-04-08
  • 1970-01-01
  • 2012-03-06
  • 2019-08-20
  • 2020-03-01
  • 2022-01-04
相关资源
最近更新 更多