views:

11111

answers:

7

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

I.e., I want to do this:

my_dict = {}

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

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

+22  A: 

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.

By the way, 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
dF
According to his example, it should be enough to set "defaultdict(lambda: 0)" and skip the entire "if" clause.
Deestan
This works, but confuses keys and values (making it somewhat odd to read). 'some_value' should be 'some_key'
nailer
@nailer: fixed, thanks. I had initially used 'some_value' since that's the variable name in the question, but I agree it's clearer now.
dF
+10  A: 

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).

Eli Bendersky
Please note that in at least 2.6 has_key() has been depricated in favor of key in d. I think it was this way in 2.5 as well.
David Locke
+1  A: 

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 (incrememnt 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

Corey Goldberg
+3  A: 

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.

ryeguy
+18  A: 

I prefer to do this in one line of code.

my_dict = {}

my_dict[some_value] = my_dict.get(some_value, 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.

Andrew Wilkinson
+4  A: 

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
bortzmeyer
has_key() is slower than the 'in' operator and is less readable.
Abgan
...and it has been deprecated in Python 2.6 and removed in Python 3.
Tim Pietzcker
+1  A: 

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).

nd