2680

I wanted to test if a key exists in a dictionary before updating the value for the key. I wrote the following code:

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

I think this is not the best way to accomplish this task. Is there a better way to test for a key in the dictionary?

bluish
  • 23,093
  • 23
  • 110
  • 171
Mohan Gulati
  • 28,129
  • 5
  • 20
  • 20
  • 31
    Calling `dict.keys()` creates a list of keys, according to the documentation http://docs.python.org/2/library/stdtypes.html#dict.keys but I'd be surprised if this pattern wasn't optimised for, in a serious implementation, to translate to `if 'key1' in dict:`. – Evgeni Sergeev Aug 12 '13 at 08:51
  • 7
    So I finally found out why many of my Python scripts were so slow :) :(. That's because I've been using `x in dict.keys()` to check for keys. And that happened because the usual way to iterate over keys in Java is `for (Type k : dict.keySet())`, this habit causing `for k in dict.keys()` to feel more natural than `for k in dict` (which should still be fine in terms of performance?), but then checking keys becomes `if k in dict.keys()` too, which is a problem... – Evgeni Sergeev Aug 12 '13 at 08:58
  • 4
    @EvgeniSergeev `if k in dict_:` tests for presence of k in the KEYS of dict_, so you still don't need `dict_.keys()`. (This has bit me, as it reads to me like its testing for a *value* in dict. But it isn't.) – ToolmakerSteve Dec 16 '13 at 23:34
  • 1
    @ToolmakerSteve That's right, but not only do you not need it, it's not a good practice. – Evgeni Sergeev Dec 17 '13 at 01:51
  • 26
    Try "key in dict" – marcelosalloum Jun 26 '14 at 17:18

16 Answers16

4168

in is the intended way to test for the existence of a key in a dict.

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

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

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

If you wanted a default, you can always use dict.get():

d = dict()

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

and if you wanted to always ensure a default value for any key you can either use dict.setdefault() repeatedly or defaultdict from the collections module, like so:

from collections import defaultdict

d = defaultdict(int)

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

but in general, the in keyword is the best way to do it.

Boris
  • 7,044
  • 6
  • 62
  • 63
Chris B.
  • 71,470
  • 23
  • 89
  • 130
  • 82
    I usually just use `get` if I'm going to be pulling the item out of the dictionary anyway. No sense in using `in` *and* pulling the item out of the dictionary. – Jason Baker Oct 21 '09 at 19:12
  • 82
    I fully agree. But if you only need to know if a key exists, or you need to distinguish between a case where the key is defined and a case where you are using a default, `in` is the best way of doing it. – Chris B. Oct 21 '09 at 19:16
  • 5
    [Reference](https://docs.python.org/3.4/library/stdtypes.html#dict) for this answer is at the python docs – enkash Jan 28 '15 at 05:54
  • @enkash provided the reference for Python 3. Here is the reference for Python 2.7: [dict](https://docs.python.org/2/library/stdtypes.html#dict) and [dict.get](https://docs.python.org/2/library/stdtypes.html#dict.get). – yaobin Jul 23 '15 at 13:00
  • 41
    get is a bad test if the key is equivalent to "False", like `0` for example. Learned this the hard way :/ – Sebastien Feb 09 '16 at 21:06
  • 5
    I can't agree that this a complete answer as it doesn't mention that 'try'-'except' will be the fastest when number of key fails is sufficiently small. See this answer below: https://stackoverflow.com/a/1602945/4376643 – Craig Hicks Oct 05 '17 at 01:18
  • You should probably also mention that `dict.has_key()`, [as described on Tutorialspoint here, for instance](https://www.tutorialspoint.com/python/dictionary_has_key.htm), has [been deprecated in Python3](https://docs.python.org/3.1/whatsnew/3.0.html): "Removed. dict.has_key() – use the `in` operator instead." – Gabriel Staples Mar 23 '20 at 06:47
  • the 2nd print statement will obviously not execute in this example! – mbyamukama Jul 27 '20 at 16:54
  • using `if "key1" in d` has a time complexity of O(n) as "key1" will be matched with every element in the dict keys. Instead use try and except KeyError and directly access d["key1"] if it exists, you will get the value else it will raise an error which is also taken care by the except statement :) Hence it happens in constant time! – TheSHETTY-Paradise Feb 28 '21 at 14:04
1633

You don't have to call keys:

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

That will be much faster as it uses the dictionary's hashing as opposed to doing a linear search, which calling keys would do.

phoenix
  • 3,988
  • 1
  • 29
  • 33
Jason Baker
  • 171,942
  • 122
  • 354
  • 501
280

You can test for the presence of a key in a dictionary, using the in keyword:

d = {'a': 1, 'b': 2}
'a' in d # <== evaluates to True
'c' in d # <== evaluates to False

A common use for checking the existence of a key in a dictionary before mutating it is to default-initialize the value (e.g. if your values are lists, for example, and you want to ensure that there is an empty list to which you can append when inserting the first value for a key). In cases such as those, you may find the collections.defaultdict() type to be of interest.

In older code, you may also find some uses of has_key(), a deprecated method for checking the existence of keys in dictionaries (just use key_name in dict_name, instead).

Michael Aaron Safyan
  • 87,518
  • 14
  • 130
  • 194
106

You can shorten this:

if 'key1' in dict:
    ...

However, this is at best a cosmetic improvement. Why do you believe this is not the best way?

Greg Hewgill
  • 828,234
  • 170
  • 1,097
  • 1,237
  • 113
    This is *much* more than a cosmetic improvement. The time to find a key using this method is O(1) whereas calling keys would generate a list and be O(n). – Jason Baker Oct 21 '09 at 19:08
  • 5
    The O(1) does not seem quite right. Are you sure it's not something like O(log n)? – spectras Aug 22 '15 at 18:08
  • 15
    It's the complexity of a single dict lookup, which is on average O(1) and at worst O(n). .list() will always be O(n). https://wiki.python.org/moin/TimeComplexity – Leonora Tindall Oct 28 '15 at 00:18
  • 1
    this also avoids an extra allocation. (important for making tight loops a bit faster) – nurettin Dec 09 '18 at 09:19
74

For additional info on speed execution of the accepted answer's proposed methods (10m loops):

  • 'key' in mydict elapsed time 1.07 sec
  • mydict.get('key') elapsed time 1.84 sec
  • mydefaultdict['key'] elapsed time 1.07 sec

Therefore using in or defaultdict are recommended against get.

Wtower
  • 15,424
  • 11
  • 94
  • 69
61

I would recommend using the setdefault method instead. It sounds like it will do everything you want.

>>> 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}
David Berger
  • 10,929
  • 6
  • 36
  • 50
  • 9
    What does `setdefault` have to do with the OP's question? – hughdbrown Oct 21 '09 at 19:11
  • 20
    @hughdbrown "I wanted to test if a key exists in a dictionary before updating the value for the key." Sometimes posts include code that generate a flurry of responses to something that's not quite the original goal. To accomplish the goal stated in the first sentence, setdefault is the most effective method, even though it's not a drop-in replacement for the sample code posted. – David Berger Oct 21 '09 at 19:14
51

Dictionary in python has a get('key', default) method. So you can just set a default value in case there is no key.

values = {...}
myValue = values.get('Key', None)
Derlin
  • 8,518
  • 2
  • 22
  • 42
mafonya
  • 1,906
  • 21
  • 19
  • The `get` method's second argument is optional and defaults to`None` if not included, so `values.get('Key', None)` is the same as `values.get('Key')`. – CodeBiker May 24 '21 at 21:19
40

What about using EAFP (easier to ask forgiveness than permission):

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

See other SO posts:

Using try vs if in python or

Checking for member existence in Python

HungryArthur
  • 878
  • 9
  • 15
  • 17
    Try/except may be more expensive if it's likely that the key often doesn't exist. From the post you referenced: "[I]f you expect that 99 % of the time result will actually contain something iterable, I'd use the try/except approach. It will be faster if exceptions really are exceptional. If result is None more than 50 % of the time, then using if is probably better.[...][A]n if statement always costs you, it's nearly free to set up a try/except block. But when an Exception actually occurs, the cost is much higher." http://stackoverflow.com/a/1835844/1094092 – billrichards Aug 19 '14 at 20:07
33

Using ternary operator:

message = "blah" if 'key1' in dict else "booh"
print(message)
Charitoo
  • 1,304
  • 12
  • 20
22

The ways in which you can get the results are:

Which is better is dependent on 3 things:

  1. Does the dictionary 'normally has the key' or 'normally does not have the key'.
  2. Do you intend to use conditions like if...else...elseif...else?
  3. How big is dictionary?

Read More: http://paltman.com/try-except-performance-in-python-a-simple-test/

Use of try/block instead of 'in' or '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."
Bishwas Mishra
  • 1,006
  • 10
  • 24
20

Python 2 only: (and python 2.7 supports `in` already)

you can use the has_key() method:

if dict.has_key('xyz')==1:
    #update the value for the key
else:
    pass
Amin Mir
  • 513
  • 4
  • 12
wan kenobi
  • 283
  • 2
  • 3
  • 26
    `.has_key()` has been [deprecated](http://docs.pythonsprints.com/python3_porting/py-porting.html#replacing-dict-has-key); you should use `in` as shown in other answers. – Brad Koch May 11 '13 at 16:50
  • 12
    BTW, I recommend reading **ALL** existing answers to an **OLD** question, before answering it. This answer added nothing, since the suggestion already existed in Michael's answer, from '09. (I don't mean to discourage an attempt to add something useful to a discussion. Keep trying.) – ToolmakerSteve Dec 16 '13 at 23:58
17

Just an FYI adding to Chris. B (best answer):

d = defaultdict(int)

Works as well; the reason is that calling int() returns 0 which is what defaultdict does behind the scenes (when constructing a dictionary), hence the name "Factory Function" in the documentation.

Mauricio Morales
  • 935
  • 9
  • 12
  • 2
    If you're creating a dictionary of counts, you should be using [Counter](http://docs.python.org/2/library/collections.html#collections.Counter) (assuming Python 2.7). And I used `defaultdict(lambda: 0)` instead of `defaultdict(int)` because I think it's clearer what's going on; the reader doesn't need to know you get `0` if you call `int()` without arguments. YMMV. – Chris B. Feb 03 '14 at 19:35
14

Check if a given key already exists in a dictionary

To get the idea how to do that we first inspect what methods we can call on dictionary. Here are the methods:

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

The brutal method to check if the key already exists may be the get() method:

d.get("key")

The other two interesting methods items() and keys() sounds like too much of work. So let's examine if get() is the right method for us. We have our dict d:

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

Printing shows the key we don't have will return None:

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

We may use that to get the info if the key is present or no. But consider this if we create a dict with a single key:None:

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

Leading that get() method is not reliable in case some values may be None. This story should have a happier ending. If we use the in comparator:

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

We get the correct results. We may examine the Python byte code:

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

This shows that in compare operator is not just more reliable but even faster than get().

prosti
  • 27,149
  • 7
  • 127
  • 118
  • `.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 Jul 05 '19 at 09:36
  • `.get()` is the fastest way. Another option is to assign in a `try`/`except` block – HCLivess Dec 30 '19 at 20:34
8

Python dictionary has the method called __contains__. This method will return True if the dictionary has the key else returns 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.
Siva Gnanam
  • 818
  • 2
  • 10
  • 25
  • 2
    It is very bad practice to call `__contains__` directly. The correct way of doing it, is to use `in` operator, which is the `containment check` that invokes the `__contains__` function. – user1767754 Nov 14 '17 at 18:21
  • @user1767754 I'm using `foo = x['foo'] if x.__contains__('foo') else 'bar'`. Any ideas how would might use the `in` operator as part of this expression? – ron_g Jan 08 '19 at 10:03
  • 1
    `foo = x['foo'] if 'foo' in x else 'bar'` – Ray Wu Jul 13 '19 at 17:11
6

Sharing one more way of checking if a key exists using boolean operators.

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

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

This returns

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

Explanation

First you should know that in Python, 0, None, or objects with zero length evaluate to False. Everything else evaluates to True. Boolean operations are evaluated left to right and return the operand not True or False.

Let's see an example:

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

Since 'Some string' evaluates to True, the rest of the or is not evaluated and there is no division by zero error raised.

But if we switch the order 1/0 is evaluated first and raises an exception:

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

We can use this for pattern for checking if a key exists.

(k in d and 'blah')

does the same as

if k in d:
    'blah'
else:
    False

This already returns the correct result if the key exists, but we want it to print 'boo' when it doesn't. So, we take the result and or it with 'boo'

>>> False or 'boo'
'boo'
>>> 'blah' or 'boo'
'blah'
>>> 
J. Antunes
  • 151
  • 2
  • 4
2

You can use for loop to iterate over the dictionary and get the name of key you want to find in the dictionary, after that check if it exist or not using if condition:

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')
Aditya
  • 445
  • 3
  • 11
Abdulkalek
  • 47
  • 3