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

Moh*_*ati 2683 python dictionary

我想在更新密钥的值之前测试字典中是否存在密钥.我写了以下代码:

if 'key1' in dict.keys():
  print "blah"
else:
  print "boo"
Run Code Online (Sandbox Code Playgroud)

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

Chr*_* B. 2980

in是测试a中密钥是否存在的预期方法dict.

d = dict()

for i in range(100):
    key = i % 10
    if key in d:
        d[key] += 1
    else:
        d[key] = 1
Run Code Online (Sandbox Code Playgroud)

如果您想要默认值,您可以随时使用dict.get():

d = dict()

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

...如果您想始终确保可以defaultdictcollections模块中使用的任何键的默认值,如下所示:

from collections import defaultdict

d = defaultdict(int)

for i in range(100):
    d[i % 10] += 1
Run Code Online (Sandbox Code Playgroud)

...但一般来说,in关键字是最好的方法.

  • 如果我打算将这个项目拉出字典,我通常只会使用`get`.使用`in`*和*将项目拉出字典是没有意义的. (66认同)
  • 我完全同意.但是,如果您只需要知道密钥是否存在,或者您需要区分定义密钥的情况和使用默认密钥的情况,那么"in"是最好的方法. (63认同)
  • 如果密钥等于"False",则get是一个错误的测试,例如`0`.很难理解:/ (24认同)
  • [参考](https://docs.python.org/3.4/library/stdtypes.html#dict)这个答案是在python docs (5认同)
  • 我不能同意这是一个完整的答案,因为它没有提到'尝试' - '除了'将是最快的,当密钥失败的数量足够小时.请参阅以下答案:/sf/answers/112206181/ (3认同)

Jas*_*ker 1479

您无需拨打密钥:

if 'key1' in dict:
  print "blah"
else:
  print "boo"
Run Code Online (Sandbox Code Playgroud)

这会更快,因为它使用字典的散列而不是进行线性搜索,调用键就可以.

  • @Mohan Gulati:你明白字典是映射到值的键的哈希表,对吧?散列算法将密钥转换为整数,整数用于在散列表中查找匹配的位置.http://en.wikipedia.org/wiki/Hash_table (48认同)
  • ivan_bilan - 我刚刚在这个问题上进行了自己的测试......在50万个键上,"如果键入d1`则需要0.17265701293945312秒.调用`如果在d1.keys()中的键'采用`0.23871088027954102` - 这是微优化的经典定义.保存`0.07884883880615234`秒不是性能提升. (11认同)
  • @Eli为了你,我创造了一个你可以自己运行的测试.结果可能让你大吃一惊.对于带有~50,000个键的dicts,不调用`keys()`会给你0.01秒的计算好处.对于~500,000个键,不调用`keys()`会给你0.1秒的好处.对于~5,000,000个键,不调用`keys()`会快0.4秒,但对于50,000,000个键**调用`键()`IS 3 SECONDS FASTER!** (10认同)
  • 那样太好了.我的印象是它内部仍会遍历键列表,但我认为这更像是测试集合中的成员资格. (6认同)
  • @Charles Addis,根据使用大约五十万个键的经验,在写入"dict in key"而不是"key in dict.keys()"时,你获得至少10倍的性能提升.PEP和Zen还声明,如果它们对您的项目不利,您应该忽略它们. (5认同)
  • @Mujtaba 也不会 `dict.keys()` (只是为了澄清) (4认同)
  • @Umimiku(及其他)。这是pycon 2010的非常有用的演示。您将看到,即使在小的记录集(<16个项目)中,冲突也会非常频繁地发生。但是python自动处理此问题。在字典中查找项目实际上与大小无关:http://pyvideo.org/pycon-us-2010/the-mighty-dictionary-55.html (2认同)
  • 不适用于嵌套值。 (2认同)

Mic*_*yan 263

您可以使用in关键字测试字典中是否存在密钥:

d = {'a': 1, 'b': 2}
'a' in d # <== evaluates to True
'c' in d # <== evaluates to False
Run Code Online (Sandbox Code Playgroud)

在变异之前检查字典中是否存在键的常见用法是默认初始化值(例如,如果您的值是列表,并且您希望确保存在可以追加的空列表插入键的第一个值时).在这种情况下,您可能会发现collections.defaultdict()感兴趣的类型.

在旧代码中,您还可以找到一些has_key()用于检查字典中键的存在的弃用方法(仅使用key_name in dict_name,而不是).

  • 想要分享(使用Python 2.7)我在很大程度上依赖于dict的内容的运行时间是使用“ key in dict.keys()”的363.235070,仅通过删除对“ keys( )” (2认同)

Gre*_*ill 95

你可以缩短这个:

if 'key1' in dict:
    ...
Run Code Online (Sandbox Code Playgroud)

然而,这充其量只是一种美容改善.为什么你认为这不是最好的方法?

  • 这比化妆品改进更多*.使用此方法查找密钥的时间是O(1),而调用密钥将生成列表并且为O(n). (95认同)
  • 这是单个dict查找的复杂性,平均为O(1),最差为O(n)..list()将始终为O(n).https://wiki.python.org/moin/TimeComplexity (9认同)
  • O(1)似乎不太正确.你确定它不像O(log n)吗? (5认同)
  • 这也避免了额外的分配。(对于使紧密循环更快一点很重要) (3认同)

Wto*_*wer 50

有关接受答案的建议方法(10米循环)的速度执行的其他信息:

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

因此使用indefaultdict建议使用get.

  • 完全同意`get`的1.84s <1.07*2 ;-P (4认同)

Dav*_*ger 48

我建议改用这种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}
Run Code Online (Sandbox Code Playgroud)

  • @hughdbrown"我想在更新密钥的值之前测试字典中是否存在密钥." 有时帖子包含的代码可以产生一些不完全是最初目标的响应.为了实现第一句中所述的目标,setdefault是最有效的方法,即使它不是发布的示例代码的替代品. (15认同)
  • "setdefault"与OP的问题有什么关系? (9认同)
  • 这是最好的答案,因为它满足了OP的目标,而不仅仅是提供技术上正确的答案.请参阅:http://nedbatchelder.com/blog/201207/bad_answers_on_stack_overflow.html (4认同)

maf*_*nya 44

python中的字典有一个get('key',default)方法.所以你可以设置一个默认值,以防没有密钥.

values = {...}
myValue = values.get('Key', None)
Run Code Online (Sandbox Code Playgroud)


Hun*_*hur 30

如何使用EAFP(更容易请求宽恕而非许可):

try:
   blah = dict["mykey"]
   # key exists in dict
except KeyError:
   # key doesn't exist in dict
Run Code Online (Sandbox Code Playgroud)

查看其他SO帖子:

在python或中使用try vs if

检查Python中的成员是否存在

  • 如果密钥通常不存在,则尝试/除可能更昂贵.从你引用的帖子开始:"[我]你希望99%的时间结果实际上包含一些可迭代的东西,我会使用try/except方法.如果异常真的很特殊,它会更快.如果结果是None超过50%的时间,然后使用if可能更好.[...] [A]如果语句总是花费你,它几乎可以自由设置一个try/except块.但是当一个Exception实际发生时,成本要高得多." http://stackoverflow.com/a/1835844/1094092 (12认同)

Cha*_*too 25

使用三元运算符:

message = "blah" if 'key1' in dict else "booh"
print(message)
Run Code Online (Sandbox Code Playgroud)


Bis*_*hra 17

您可以获得结果的方式是:

哪个更好取决于3件事:

  1. 字典'通常是否有密钥'或'通常没有密钥'.
  2. 你是否打算使用if ...... else ...... elseif ...... else等条件?
  3. 字典有多大?

阅读更多: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."
Run Code Online (Sandbox Code Playgroud)

  • 很好,但是需要针对python 3实现。我使用`2to3`转换了网页脚本,并且发现即使try键位于dict中,不带try语法总是比带try语法更快。 (2认同)

小智 16

您可以使用has_key()方法:

if dict.has_key('xyz')==1:
    #update the value for the key
else:
    pass
Run Code Online (Sandbox Code Playgroud)

或者in如果找不到则设置默认值的方法:

if dict.has_key('xyz')==1:
    #update the value for the key
else:
    pass
Run Code Online (Sandbox Code Playgroud)

  • `.has_key()`已经[已弃用](http://docs.pythonsprints.com/python3_porting/py-porting.html#replacing-dict-has-key); 你应该使用`in`,如其他答案所示. (20认同)
  • 顺便说一句,我建议在回答之前阅读******现有答案****OLD**问题.这个答案没有任何补充,因为这个建议已经存在于Michael的回答中,从'09开始.(我的意思是不鼓励尝试在讨论中添加有用的东西.继续尝试.) (12认同)

Mau*_*les 15

只是一个FYI加入克里斯.B(最佳答案):

d = defaultdict(int)
Run Code Online (Sandbox Code Playgroud)

也适用; 原因是调用int()返回0defaultdict幕后的(当构造字典时),因此文档中的名称为"Factory Function".

  • 如果你要创建一个计数字典,你应该使用[Counter](http://docs.python.org/2/library/collections.html#collections.Counter)(假设是Python 2.7).我使用`defaultdict(lambda:0)`而不是`defaultdict(int)`因为我认为它更清楚发生了什么; 如果你在没有参数的情况下调用`int()`,读者不需要知道你得到'0`.因人而异. (2认同)

Siv*_*nam 8

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.
Run Code Online (Sandbox Code Playgroud)

  • 直接调用`__contains__`是非常糟糕的做法.这样做的正确方法是使用`in`操作符,这是调用`__contains__`函数的`containment check`. (2认同)
  • `foo = x['foo'] if 'foo' in x else 'bar'` (2认同)

小智 6

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

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

for k in keys:
    x = (k in d and 'blah') or 'boo'
    print(x) 
Run Code Online (Sandbox Code Playgroud)

这返回

>>> blah
>>> blah
>>> boo
>>> boo
Run Code Online (Sandbox Code Playgroud)

解释

首先你应该知道在 Python 中,0, None, 或长度为零的对象计算为False. 其他一切都评估为True. 布尔运算从左到右计算,并返回非 True 或 False 的操作数。

让我们看一个例子:

>>> 'Some string' or 1/0 
'Some string'
>>>
Run Code Online (Sandbox Code Playgroud)

由于'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
>>> 
Run Code Online (Sandbox Code Playgroud)

我们可以将其用于模式来检查密钥是否存在。

(k in d and 'blah')
Run Code Online (Sandbox Code Playgroud)

if k in d:
    'blah'
else:
    False
Run Code Online (Sandbox Code Playgroud)

如果键存在,这已经返回正确的结果,但我们希望它在不存在时打印 'boo'。所以,我们把结果和or'boo'

>>> False or 'boo'
'boo'
>>> 'blah' or 'boo'
'blah'
>>> 
Run Code Online (Sandbox Code Playgroud)


pro*_*sti 6

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

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

d={'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

检查密钥是否已存在的残酷方法可能是get()

d.get("key")
Run Code Online (Sandbox Code Playgroud)

其他两种有趣的方法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}
Run Code Online (Sandbox Code Playgroud)

打印显示我们没有的密钥将返回None

print(d.get('key')) #None
print(d.get('clear')) #0
print(d.get('copy')) #1
Run Code Online (Sandbox Code Playgroud)

如果密钥存在或不存在,我们可能会用它来获取信息。但是,如果我们使用单个命令创建字典,请考虑以下问题key:None

d= {'key':None}
print(d.get('key')) #None
print(d.get('key2')) #None
Run Code Online (Sandbox Code Playgroud)

get()如果某些值可能是,导致该方法不可靠None。这个故事的结局应该更快乐。如果我们使用in比较器:

print('key' in d) #True
print('key2' in d) #False
Run Code Online (Sandbox Code Playgroud)

我们得到正确的结果。我们可以检查一下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
Run Code Online (Sandbox Code Playgroud)

这表明in比较运算符不仅比更加可靠,而且甚至更快get()