311
votes

Given a dictionary, how can I find out if a given key in that dictionary has already been set to a non-None value?

I.e., I want to do this:

my_dict = {}

if (my_dict[key] != None):
  my_dict[key] = 1
else:
  my_dict[key] += 1

I.e., I want to increment the value if there's already one there, or set it to 1 otherwise.

12
Small code nitpick: the code sets my_dict[key] to 1 if there's already something there, and increments it if there isn't. I think you want ==, not !=. - QuantumFool

12 Answers

342
votes

You are looking for collections.defaultdict (available for Python 2.5+). This

from collections import defaultdict

my_dict = defaultdict(int)
my_dict[key] += 1

will do what you want.

For regular Python dicts, if there is no value for a given key, you will not get None when accessing the dict -- a KeyError will be raised. So if you want to use a regular dict, instead of your code you would use

if key in my_dict:
    my_dict[key] += 1
else:
    my_dict[key] = 1
322
votes

I prefer to do this in one line of code.

my_dict = {}

my_dict[some_key] = my_dict.get(some_key, 0) + 1

Dictionaries have a function, get, which takes two parameters - the key you want, and a default value if it doesn't exist. I prefer this method to defaultdict as you only want to handle the case where the key doesn't exist in this one line of code, not everywhere.

62
votes

I personally like using setdefault()

my_dict = {}

my_dict.setdefault(some_key, 0)
my_dict[some_key] += 1
50
votes

You need the key in dict idiom for that.

if key in my_dict and not (my_dict[key] is None):
  # do something
else:
  # do something else

However, you should probably consider using defaultdict (as dF suggested).

20
votes

To answer the question "how can I find out if a given index in that dict has already been set to a non-None value", I would prefer this:

try:
  nonNone = my_dict[key] is not None
except KeyError:
  nonNone = False

This conforms to the already invoked concept of EAFP (easier to ask forgiveness then permission). It also avoids the duplicate key lookup in the dictionary as it would in key in my_dict and my_dict[key] is not None what is interesting if lookup is expensive.

For the actual problem that you have posed, i.e. incrementing an int if it exists, or setting it to a default value otherwise, I also recommend the

my_dict[key] = my_dict.get(key, default) + 1

as in the answer of Andrew Wilkinson.

There is a third solution if you are storing modifyable objects in your dictionary. A common example for this is a multimap, where you store a list of elements for your keys. In that case, you can use:

my_dict.setdefault(key, []).append(item)

If a value for key does not exist in the dictionary, the setdefault method will set it to the second parameter of setdefault. It behaves just like a standard my_dict[key], returning the value for the key (which may be the newly set value).

14
votes

Agreed with cgoldberg. How I do it is:

try:
    dict[key] += 1
except KeyError:
    dict[key] = 1

So either do it as above, or use a default dict as others have suggested. Don't use if statements. That's not Pythonic.

11
votes

As you can see from the many answers, there are several solutions. One instance of LBYL (look before you leap) has not been mentioned yet, the has_key() method:

my_dict = {}

def add (key):
    if my_dict.has_key(key):
        my_dict[key] += 1
    else:
        my_dict[key] = 1

if __name__ == '__main__':
    add("foo")
    add("bar")
    add("foo")
    print my_dict
8
votes

A bit late but this should work.

my_dict = {}
my_dict[key] = my_dict[key] + 1 if key in my_dict else 1
7
votes

The way you are trying to do it is called LBYL (look before you leap), since you are checking conditions before trying to increment your value.

The other approach is called EAFP (easier to ask forgiveness then permission). In that case, you would just try the operation (increment the value). If it fails, you catch the exception and set the value to 1. This is a slightly more Pythonic way to do it (IMO).

http://mail.python.org/pipermail/python-list/2003-May/205182.html

5
votes

This isn't directly answering the question, but to me, it looks like you might want the functionality of collections.Counter.

from collections import Counter

to_count = ["foo", "foo", "bar", "baz", "foo", "bar"]

count = Counter(to_count)

print(count)

print("acts just like the desired dictionary:")
print("bar occurs {} times".format(count["bar"]))

print("any item that does not occur in the list is set to 0:")
print("dog occurs {} times".format(count["dog"]))

print("can iterate over items from most frequent to least:")
for item, times in count.most_common():
    print("{} occurs {} times".format(item, times))

This results in the output

Counter({'foo': 3, 'bar': 2, 'baz': 1})
acts just like the desired dictionary:
bar occurs 2 times
any item that does not occur in the list is set to 0:
dog occurs 0 times
can iterate over items from most frequent to least:
foo occurs 3 times
bar occurs 2 times
baz occurs 1 times
3
votes

Here's one-liner that I came up with recently for solving this problem. It's based on the setdefault dictionary method:

my_dict = {}
my_dict[key] = my_dict.setdefault(key, 0) + 1
-1
votes

I was looking for it, didn't found it on web then tried my luck with Try/Error and found it

my_dict = {}

if my_dict.__contains__(some_key):
  my_dict[some_key] += 1
else:
  my_dict[some_key] = 1