ChatGPT解决这个技术问题 Extra ChatGPT

检查给定键是否已存在于字典中

这个问题的答案是社区的努力。编辑现有答案以改进这篇文章。它目前不接受新的答案或交互。

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

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

我认为这不是完成这项任务的最佳方式。有没有更好的方法来测试字典中的键?

根据文档 docs.python.org/2/library/stdtypes.html#dict.keys,调用 dict.keys() 会创建一个键列表,但如果此模式没有针对在严肃实现中转换为 if 'key1' in dict: 进行优化,我会感到惊讶。
所以我终于发现了为什么我的许多 Python 脚本都这么慢 :) :(。那是因为我一直在使用 x in dict.keys() 来检查键。发生这种情况是因为在 Java 中迭代键的常用方法是 {2 },这个习惯导致 for k in dict.keys() 感觉比 for k in dict 更自然(在性能方面应该仍然没问题?),但是检查键也变成 if k in dict.keys(),这是一个问题......
@EvgeniSergeev if k in dict_: 测试 dict_ 的 KEYS 中是否存在 k,因此您仍然不需要 dict_.keys()。 (这让我很生气,因为它读起来就像它在 dict 中测试 value 一样。但事实并非如此。)
@ToolmakerSteve 没错,但您不仅不需要它,这不是一个好习惯。
尝试“输入字典”

B
Boris Verkhovskiy

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(10):
    d[i] = d.get(i, 0) + 1

要为 每个 键提供默认值,请在每个分配上使用 dict.setdefault()

d = {}

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

或使用 collections 模块中的 defaultdict

from collections import defaultdict

d = defaultdict(int)

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

如果无论如何我要从字典中提取项目,我通常只使用 get。使用 in and 将项目从字典中拉出是没有意义的。
我完全同意。但是,如果您只需要知道某个键是否存在,或者您需要区分定义键的情况和使用默认键的情况,in 是最好的方法。
@enkash 提供了 Python 3 的参考。这里是 Python 2.7 的参考:dictdict.get
如果键等于“False”,例如 0,则 get 是一个不好的测试。很难学到这一点:/
我不能同意这是一个完整的答案,因为它没有提到当密钥失败的数量足够小时时,'try'-'except' 将是最快的。请参阅下面的答案:stackoverflow.com/a/1602945/4376643
p
phoenix

您不必调用密钥:

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

这将是很多 faster,因为它使用字典的散列而不是进行线性搜索,调用键会这样做。


不适用于嵌套值。
M
Michael Aaron Safyan

您可以使用 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)。


B
Bgil Midol

您可以将代码缩短为:

if 'key1' in my_dict:
    ...

然而,这充其量只是外观上的改进。为什么你认为这不是最好的方法?


这不仅仅是外观上的改进。使用这种方法找到一个键的时间是 O(1),而调用键会生成一个列表并且是 O(n)。
O(1) 似乎不太正确。你确定这不是 O(log n) 之类的东西吗?
这是单个 dict 查找的复杂性,平均为 O(1),最坏的情况为 O(n)。 .list() 将始终为 O(n)。 wiki.python.org/moin/TimeComplexity
这也避免了额外的分配。 (对于使紧密循环更快一点很重要)
P
Peter Mortensen

有关 accepted answer's 建议方法(10 M 循环)的速度执行的更多信息:

mydict 中的“key”经过时间 1.07 秒

mydict.get('key') 经过时间 1.84 秒

mydefaultdict['key'] 经过时间 1.07 秒

因此,建议对 get 使用 indefaultdict


完全同意 get 的 1.84s 是 < 1.07*2 ;-P
D
David Berger

我建议改用 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}

setdefault 与 OP 的问题有什么关系?
@hughdbrown“我想在更新键的值之前测试字典中是否存在键。”有时,帖子包含的代码会产生一系列对不完全是最初目标的东西的响应。为了实现第一句中所述的目标,setdefault 是最有效的方法,即使它不是发布的示例代码的直接替代品。
P
Peter Mortensen

Python 中的字典有一个 get('key', default) 方法。所以你可以设置一个默认值,以防没有任何键。

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

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

使用 Python ternary operator

message = "blah" if 'key1' in my_dict else "booh"
print(message)

P
Peter Mortensen

使用 EAFP(请求宽恕比请求许可更容易):

try:
   blah = dict["mykey"]
   # key exists in dict
except KeyError:
   # key doesn't exist in dict

查看其他堆栈溢出帖子:

在 Python 中使用“try”与“if”

在 Python 中检查成员是否存在


如果密钥可能经常不存在,那么 Try/except 可能会更昂贵。从您引用的帖子中:“[I]如果您希望 99 % 的时间结果实际上包含可迭代的东西,我会使用 try/except 方法。如果异常确实是异常的,它会更快。如果结果是 None超过 50% 的时间,那么使用 if 可能会更好。[...][A]n if 语句总是要花费你,设置 try/except 块几乎是免费的。但是当实际发生异常时,成本要高得多。” stackoverflow.com/a/1835844/1094092
P
Peter Mortensen

检查给定键是否已存在于字典中

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

以下是方法:

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() 可以为 default 值提供第二个参数,可用于处理 key:None 的问题。示例:d.get("key", False)
.get() 是最快的方法。另一种选择是在 try/except 块中分配
B
Bishwas Mishra

获得结果的方法有:

if your_dict.has_key(key) 在 Python 3 中被移除

如果键入 your_dict

尝试/排除块

哪个更好取决于三件事:

字典是“通常有钥匙”还是“通常没有钥匙”。您是否打算使用 if...else...elseif...else 之类的条件?字典有多大?

阅读更多:http://paltman.com/try-except-performance-in-python-a-simple-test/

使用 try/block 代替 'in' 或 'if':

try:
    my_dict_of_items[key_i_want_to_check]
except KeyError:
    # Do the operation you wanted to do for "key not present in dict".
else:
    # Do the operation you wanted to do with "key present in dict."

P
Peter Mortensen

仅限 Python 2:(并且 Python 2.7 已经支持 `in`)

您可以使用 has_key() 方法:

if dict.has_key('xyz')==1:
    # Update the value for the key
else:
    pass

.has_key() 已成为 deprecated;您应该使用 in,如其他答案所示。
顺便说一句,我建议在回答之前阅读旧问题的所有现有答案。这个答案没有增加任何内容,因为从 09 年开始,迈克尔的答案中已经存在该建议。 (我并不是要阻止尝试在讨论中添加一些有用的东西。继续尝试。)
P
Peter Mortensen

只是添加到 Chris. B's (best) answer 的 FYI:

d = defaultdict(int)

也可以;原因是调用 int() 返回 0,这是 defaultdict 在幕后所做的(在构造字典时),因此文档中的名称为“Factory Function”。


如果要创建计数字典,则应使用 Counter(假设 Python 2.7)。我使用 defaultdict(lambda: 0) 而不是 defaultdict(int) 因为我认为发生了什么更清楚;如果您在没有参数的情况下调用 int(),则读者不需要知道您会得到 0。 YMMV。
P
Peter Mortensen

Python 字典具有称为 __contains__ 的方法。如果字典有键,此方法将返回 True,否则返回 False。

>>> temp = {}

>>> help(temp.__contains__)

Help on built-in function __contains__:

__contains__(key, /) method of builtins.dict instance
    True if D has a key k, else False.

直接调用 __contains__ 是非常糟糕的做法。正确的做法是使用 in 运算符,即调用 __contains__ 函数的 containment check
@user1767754 我正在使用 foo = x['foo'] if x.__contains__('foo') else 'bar'。任何想法如何将 in 运算符用作此表达式的一部分?
foo = x['foo'] if 'foo' in x else 'bar'
P
Peter Mortensen

另一种使用布尔运算符检查键是否存在的方法:

d = {'a': 1, 'b':2}
keys = 'abcd'

for k in keys:
    x = (k in d and 'blah') or 'boo'
    print(x)

这返回

>>> blah
>>> blah
>>> boo
>>> boo

解释

首先,您应该知道,在 Python 中,0None 或长度为零的对象的计算结果为 False。其他所有内容的计算结果为 True。布尔运算从左到右求值并返回操作数不是 True 或 False。

让我们看一个例子:

>>> 'Some string' or 1/0
'Some string'
>>>

由于 'Some string' 的计算结果为 True,因此 or 的其余部分不会被计算,并且不会引发除以零错误。

但是如果我们切换顺序 1/0 会首先被评估并引发异常:

>>> 1/0 or 'Some string'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>>

我们可以使用这个模式来检查一个键是否存在。

(k in d and 'blah')

if k in d:
    'blah'
else:
    False

如果密钥存在,这已经返回正确的结果,但我们希望它在不存在时打印“boo”。因此,我们获取结果并使用 'boo' or

>>> False or 'boo'
'boo'
>>> 'blah' or 'boo'
'blah'
>>>

P
Peter Mortensen

您可以使用 for 循环遍历字典并获取要在字典中查找的键的名称。之后,使用 if 条件检查它是否存在:

dic = {'first' : 12, 'second' : 123}
for each in dic:
    if each == 'second':
        print('the key exists and the corresponding value can be updated in the dictionary')

检查代码,因为它的输出是 it is existnot exist
如果这是为了执行线性搜索,为什么还要使用字典?