views:

1653

answers:

5

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?

+18  A: 

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.

Jason Baker
That is great. I was under the impression that it would internally still traverse the list of keys, but I see this works more like testing membership in a set.
Mohan Gulati
@Mohan Gulati: You understand that a dictionary is a hashtable of keys mapped to values, right? A hashing algorithm converts the key to an integer and the integer is used to find a location in the hash table that matches. http://en.wikipedia.org/wiki/Hash_table
hughdbrown
+3  A: 

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
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
Good point. +1 to your answer.
Greg Hewgill
+4  A: 

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
What does `setdefault` have to do with the OP's question?
hughdbrown
@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
+10  A: 

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

d = dict()

for i in xrange(100):
    key = i % 10
    if key in d:
        d[key] += 1
    else:
        d[key] = 1

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

d = dict()

for i in xrange(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 use defaultdict from the collections module, like so:

from collections import defaultdict

d = defaultdict(lambda: 0)

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

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

Chris B.
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
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.
Thanks guys... great feedback. I am understanding the subtleties of the language better with each of your replies.
Mohan Gulati
+1  A: 

There are two different ways to do it:

  1. key in dict
  2. dict.has_key(key)

You might also want to check out the Python Quick Reference.

EDIT:

As noted, "has_key" is deprecated in Python 3.0+.

Michael Aaron Safyan
dict.has_key(key) has been deprecated in favor of key in dict
David Locke
@David, thanks... I haven't really looked at 3.0, yet.
Michael Aaron Safyan