检查一个给定的键是否已经存在于字典中。

2678

我想在更新字典里的值之前测试一个键是否存在。我编写了以下代码:

if 'key1' in dict.keys():
  print "blah"
else:
  print "boo"

我认为这不是完成此任务的最佳方式。有更好的方法来测试字典中是否存在某个键吗?


31
调用dict.keys()会创建一个键列表,根据文档http://docs.python.org/2/library/stdtypes.html#dict.keys的说明。但是如果在实际的实现中没有对这种模式进行优化以转换为`if 'key1' in dict:`,那么我会感到惊讶。 - Evgeni Sergeev
7
所以,我最终发现为什么我的许多Python脚本非常缓慢 :(。这是因为我一直在使用x in dict.keys()来检查键。这是因为在Java中迭代键的通常方式是for (Type k:dict.keySet()),养成了这个习惯,导致for k in dict.keys()for k in dict(在性能方面仍然可以)更加自然,但是检查键也变成了if k in dict.keys(),这是一个问题... - Evgeni Sergeev
4
if k in dict_: 判断 k 是否在字典 dict_ 的键中,所以你仍然不需要使用 dict_.keys()。(这个问题曾经让我误解,因为它听起来像是在测试字典中的是否存在。但实际上不是这样。) - ToolmakerSteve
1
@ToolmakerSteve 是的,但你不仅不需要它,而且这也不是一个好的做法。 - Evgeni Sergeev
26
尝试使用 "key in dict"。 - marcelosalloum
16个回答

5339

in 用于测试一个键是否存在于 dict 中:

d = {"key1": 10, "key2": 23}

if "key1" in d:
    print("this will execute")

if "nonexistent key" in d:
    print("this will not")

使用 dict.get() 在键不存在时提供默认值:

d = {}

for i in range(100):
    key = i % 10
    d[key] = d.get(key, 0) + 1

为每个键提供默认值,可以在每次赋值时使用 dict.setdefault()
d = {}

for i in range(100):
    d[i % 10] = d.setdefault(i % 10, 0) + 1    

...或者更好的方法,使用collections模块中的defaultdict:

from collections import defaultdict

d = defaultdict(int)

for i in range(100):
    d[i % 10] += 1

95
如果我要从字典中提取项,通常只需使用“get”。使用“in”和从字典中提取项没有意义。 - Jason Baker
101
我完全同意。但是如果您只需知道一个键是否存在,或者需要区分一个键是否被定义和使用默认值的情况下,"in" 是最好的方法。 - Chris B.
@enkash 提供了 Python 3 的参考文献。这里是 Python 2.7 的参考文献:dictdict.get - yaobin
62
如果密钥等于“False”,例如0,那么使用get是一个糟糕的测试。我通过困难的方式学到了这一点 :/ - Sebastien
6
我不同意这是一个完整的答案,因为它没有提到当键值失败的数量足够小的时候,'try-except'将是最快的方法。 请参考下面的答案:https://dev59.com/Q3I-5IYBdhLWcg3w8dUQ#1602945 - Craig Hicks
显示剩余4条评论

1871

直接使用 key in my_dict,而不是 key in my_dict.keys()

if 'key1' in my_dict:
    print("blah")
else:
    print("boo")

使用字典的O(1)哈希查找,要比对键列表进行O(n)线性搜索明显更快(更多详情)


2
无法处理嵌套值。 - Mujtaba
3
@Mujtaba,也不是 dict.keys()(只是澄清一下) - Matt

295
你可以使用in关键字测试字典中是否存在某个键:
d = {'a': 1, 'b': 2}
'a' in d # <== evaluates to True
'c' in d # <== evaluates to False

在字典中对键进行变化之前常常需要检查该键是否存在,以便默认初始化值(例如,如果您的值是列表,并且想要确保在为键插入第一个值时有一个空列表可以添加)。在这种情况下,您可能会发现 collections.defaultdict() 类型很有用。

在旧代码中,您可能还会发现使用 has_key() 的一些用法,该方法已被弃用用于检查字典中的键是否存在(只需使用 key_name in dict_name 即可)。


180

你可以将代码缩短为以下内容:

if 'key1' in my_dict:
    ...

然而,这最多只是一个表面上的改进。你为什么认为这不是最好的方法?


132
这不仅仅是表面上的改进。使用这种方法查找一个键所需的时间是O(1),而调用键将生成一个列表,并且是O(n)。 - Jason Baker
6
O(1)似乎不太正确。你确定它不是类似于O(log n)的东西吗? - spectras
17
这句话的意思是,单个字典查找的复杂度在平均情况下为O(1),最差情况下为O(n)。使用.list()方法的时间复杂度总是O(n)。 - Leonora Tindall
3
这也避免了额外的分配。(对于使紧密循环变得更快非常重要) - nurettin
@JasonBaker 调用.keys在2.x中只生成一个列表或需要O(n)时间(和内存)。 在3.x中,它创建了一个特殊的视图对象,类似于2.x的.iterkeys。 但是,它仍然增加了不必要的复杂性和开销。 - Karl Knechtel
如果键不是字符串怎么办? - Mehdi Charife

99

有关于答案被采纳者提出的方法(1000万次循环)的速度执行的额外信息:

  • 'key' in mydict 执行时间1.07秒
  • mydict.get('key') 执行时间1.84秒
  • mydefaultdict['key'] 执行时间1.07秒

因此,使用 indefaultdict 比使用get 更推荐。


12
完全同意 get 的 1.84 秒 < 1.07*2 ;-P。 - Paul Rigor

65

我建议使用setdefault方法。听起来它会满足你的所有需求。

>>> d = {'foo':'bar'}
>>> q = d.setdefault('foo','baz') #Do not override the existing key
>>> print q #The value takes what was originally in the dictionary
bar
>>> print d
{'foo': 'bar'}
>>> r = d.setdefault('baz',18) #baz was never in the dictionary
>>> print r #Now r has the value supplied above
18
>>> print d #The dictionary's been updated
{'foo': 'bar', 'baz': 18}

11
setdefault跟原帖的问题有什么关系? - hughdbrown
21
“我想测试一下字典里是否存在某个键,再更新该键对应的值。” 有时候帖子中包含的代码会引发一系列回复,但这些回复并没有解决最初的目标。要实现第一句话所述的目标,setdefault 是最有效的方法,尽管它不能直接替换原始发布的示例代码。 - David Berger

60

Python中的字典有一个get('键', 默认值)方法。所以你可以在没有键的情况下设置一个默认值。

values = {...}
myValue = values.get('Key', None)

1
get方法的第二个参数是可选的,如果未包含则默认为None,因此values.get('Key', None)values.get('Key')相同。 - CodeBiker

56

51

21
如果键通常不存在,使用try/except可能会更昂贵。引用的帖子中写道:“如果你预计99%的时间结果实际上包含可迭代的内容,那么我会使用try/except方法。如果异常确实是例外情况,那么这将更快。如果结果为None的时间超过50%,则使用if语句可能更好[...] if语句始终会产生成本,在设置try/except块时几乎没有成本。但是当出现异常时,成本要高得多。” https://dev59.com/XnI-5IYBdhLWcg3weoPR#1835844 - billrichards

32

检查字典中是否存在给定的键。

为了想出如何做到这一点,我们首先检查可以在字典上调用哪些方法。

以下是可用的方法:

d={'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}

Python Dictionary clear()        Removes all Items
Python Dictionary copy()         Returns Shallow Copy of a Dictionary
Python Dictionary fromkeys()     Creates dictionary from given sequence
Python Dictionary get()          Returns Value of The Key
Python Dictionary items()        Returns view of dictionary (key, value) pair
Python Dictionary keys()         Returns View Object of All Keys
Python Dictionary pop()          Removes and returns element having given key
Python Dictionary popitem()      Returns & Removes Element From Dictionary
Python Dictionary setdefault()   Inserts Key With a Value if Key is not Present
Python Dictionary update()       Updates the Dictionary
Python Dictionary values()       Returns view of all values in dictionary

检查键是否已存在的残酷方法可能是使用 get() 方法:

d.get("key")

另外两种有趣的方法items()keys()听起来需要做很多工作。所以让我们检查一下get()是否是适合我们的正确方法。我们有一个字典d:

d= {'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}

打印一个不存在的键,将返回None

print(d.get('key')) #None
print(d.get('clear')) #0
print(d.get('copy')) #1

我们使用它来获取键是否存在的信息。但是请考虑如果我们创建一个只有一个key: None的字典:

d= {'key':None}
print(d.get('key')) #None
print(d.get('key2')) #None

在某些值可能为 None 的情况下,使用 get() 方法不可靠。

这个故事应该有一个更加美好的结局。如果我们使用 in 比较符:

print('key' in d) #True
print('key2' in d) #False

我们得到了正确的结果。

我们可以检查Python字节码:

import dis
dis.dis("'key' in d")
#   1           0 LOAD_CONST               0 ('key')
#               2 LOAD_NAME                0 (d)
#               4 COMPARE_OP               6 (in)
#               6 RETURN_VALUE

dis.dis("d.get('key2')")
#   1           0 LOAD_NAME                0 (d)
#               2 LOAD_METHOD              1 (get)
#               4 LOAD_CONST               0 ('key2')
#               6 CALL_METHOD              1
#               8 RETURN_VALUE

这表明in比较运算符不仅更可靠,而且速度比get()还要快。


.get() can have a second argument for default value, that couldbe used to handle the issue where key:None. example: d.get("key", False) - Alex
.get() 是最快的方法。 另一个选项是在 try/except 块中进行赋值。 - HCLivess

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