如果字典中不存在某个键,返回默认值。

760

如果键存在,我需要一种获取字典值的方法,否则只返回None

然而,如果搜索不存在的键,Python会引发一个KeyError异常。我知道我可以检查键是否存在,但我正在寻找更明确的方法。是否有一种方式,如果键不存在,就只返回None


另请参阅:为什么使用 dict.get(key) 而不是 dict[key]?


123
请使用.get(key)代替[key] - Gabe
3
在Python中,访问键并捕获异常是完全可以的。这甚至是一个广为人知且经常使用的设计模式。如果你返回None,就无法将其作为值存储,这在某些情况下可能很重要。 - Ber
1
有时候你想把字典中的“None”条目和缺失的条目视为同一种情况,这种情况下接受的答案似乎可以很好地完成工作。 - cib
15个回答

1268

你可以使用dict.get()方法。

value = d.get(key)

如果 key 不在字典 d 中,将返回None。您还可以提供一个不同的默认值,代替None

value = d.get(key, "empty")

92
请注意,如果字典中的键明确映射到None,则使用默认回退的第二个变体仍将返回None。 如果这不是您想要的结果,您可以使用类似于d.get(key) or "empty"的方法。 - cib
25
@cib: 很好的观点,但解决方案存在类似的问题 - 如果键映射到任何“falsy”值(如[]""False0.0或确切地说是None),那么你的解决方案将始终返回0。如果你期望值为None,则需要显式执行if key in d:检查。 - Tim Pietzcker
1
@cib 谢谢你,我在这里做错了什么一直想不明白。 - wobbily_col
啊,现在我明白你的意思了。我没有仔细阅读你的问题。我看着我的答案(d.get(key, "empty"),它没有这个问题),而不是 or 变体。 - Tim Pietzcker
一个关于海象操作符的例子会很酷。 - Charlie Parker
显示剩余3条评论

71

不必再猜测,这已经内置在语言中了。

    >>> help(dict)
在模块builtins中的class dict(object)上提供帮助文档:
class dict(object) | dict() -> 新空字典 | dict(mapping) -> 新字典,从映射对象的(key, value)对进行初始化 ... | | get(...) | D.get(k[,d]) -> 如果k在D中,则返回D[k],否则返回d。默认为None。 | ...

35

使用 dict.get

如果key在字典中,则返回key对应的值,否则返回默认值。如果没有提供默认值,则默认为None,因此该方法永远不会引发KeyError异常。


35
你应该使用字典类的 get() 方法。
d = {}
r = d.get('missing_key', None)

这将导致r == None。 如果字典中没有找到键,则get函数将返回第二个参数。


31
无需明确传递None,它是默认值。 - Björn Pollex

25

如果你想要一个更透明的解决方案,你可以子类化dict来得到这种行为:

class NoneDict(dict):
    def __getitem__(self, key):
        return dict.get(self, key)

>>> foo = NoneDict([(1,"asdf"), (2,"qwerty")])
>>> foo[1]
'asdf'
>>> foo[2]
'qwerty'
>>> foo[3] is None
True

2
正如我在另一个答案的评论中提到的那样,defaultdict 的问题在于每次请求一个尚未存在的元素时它都会增长。这并不总是理想的。 - Björn Pollex
2
@BjörnPollex 这绝对是最优雅的方法,你有没有什么线索可以扩展它以支持任意深度?我的意思是使 foo['bar']['test']['sss'] 返回 None 而不是异常。在一定深度后,它开始给出 TypeError 而不是 KeyError - nehem
@itsneo。您可以构建整个“NoneDicts”的结构。这将有助于在最内层对象发生“KeyError”时解决问题。否则,问题在于一旦返回一个“None”对象,就无法再订阅它了。一个丑陋的hack是返回另一个类似于“None”的对象。但请注意,这可能会导致可怕的错误。 - magu_
@BjörnPollex 把 return dict.get(self, key) 改成 return super().get(key) 可以吗?这样如果我决定使用 OrderedDict 而不是 dict,就不必担心需要改动多行代码了。 - Wood
@Wood 是的,那样会更好! - Björn Pollex
显示剩余3条评论

24

我通常在这种情况下使用defaultdict。您提供一个不带参数的工厂方法,当它遇到新键时创建一个值。在想要在新键上返回空列表时,它更有用(请参阅示例)。

from collections import defaultdict
d = defaultdict(lambda: None)
print d['new_key']  # prints 'None'

21
defaultdict 的问题在于每次请求不存在的元素时它都会不断增长。 - Björn Pollex
这也可以是期望的行为,比如当您尝试使用循环构建嵌套字典时。 - Dre

13

一行解决方案如下:

item['key'] if 'key' in item else None

当尝试将字典值添加到新列表并希望提供默认值时,这非常有用:

例如:

row = [item['key'] if 'key' in item else 'default_value']

这是一个非常有趣的方法。感谢您添加这个答案。我一定会探索这个用例。 - Carewen

12

如其他人所说,您可以使用get()方法。

但是,要检查一个键是否存在,您也可以这样做:

d = {}
if 'keyname' in d:

    # d['keyname'] exists
    pass

else:

    # d['keyname'] does not exist
    pass

我现在看到你已经知道如何做了。我本来想删除我的帖子,但为了其他人的参考,我会把它留下来。 - Marek P
4
这种方法通常需要在密钥存在时进行两次查找,这可能是“get”方法存在的原因。 - martineau

10

你可以使用字典对象的get()方法,就像其他人已经建议的那样。或者,根据你实际需要做什么,你也可以像这样使用try/except语句块:

try:
   <to do something with d[key]>
except KeyError:
   <deal with it not being there>

这被认为是一种非常“Pythonic”的处理方式。


我认为这会违反“显式优于隐式”的原则,使意图不明确。更不用说脆弱性和冗长性了。 - Haroldo_OK
@Haroldo_OK:我非常不同意,它非常明确。 - martineau
我倾向于同意这实际上是一种非常明确的方法。虽然它会导致更多的代码行数(get() 实际上只有一行),但它非常易读。 - Carewen

3

对于那些使用 dict.get 技术来处理嵌套字典的人,不需要显式地检查字典的每个级别或扩展 dict 类,可以将默认返回值设置为除最外层之外的空字典。下面是一个例子:

my_dict = {'level_1': {
             'level_2': {
                  'level_3': 'more_data'
                  }
              }
           }
result = my_dict.get('level_1', {}).get('level_2', {}).get('level_3')
# result -> 'more_data'
none_result = my_dict.get('level_1', {}).get('what_level', {}).get('level_3')
# none_result -> None

警告:请注意,此技术仅适用于预期的键值为字典的情况。如果字典中存在 what_level 键,但其值为字符串或整数等,则会引发 AttributeError


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接