2

Suppose I have dictionary and I want to fill that with some keys and values , first dictionary is empty and suppose I need this dictionary for a counter for example count some keys in a string I have this way:

myDic = {}
try :
    myDic[desiredKey] += 1
except KeyError:
    myDic[desiredKey] = 1

Or maybe some times values should be a list and I need to append some values to a list of values I have this way:

myDic = {}
try:
    myDic[desiredKey].append(desiredValue)
except KeyError:
    myDic[desiredKey] = []
    myDic[desiredKey].append(desiredValue)

Is there better alternarive for this works (both of them) that dont uses try except section?

ᴀʀᴍᴀɴ
  • 4,443
  • 8
  • 37
  • 57

4 Answers4

3

I suggest collections.defaultdict

from collections import defaultdict
myDic = defaultdict(int)
myDic[key] = value

as Two-Bit Alchemist adequately put, the best thing about defaultdict is when you need multiple value keys(without having to define the value as a list first). Using d["key"] = value again would just reset the old value, So:

myDic = defaultdict(list)
for key in keys_list:
    myDic[key].append(value)
Rockybilly
  • 2,938
  • 1
  • 13
  • 38
  • 1
    Do an example with this using the list one. That's where this solution really shines. (Also you might explain that `defaultdict(int)` means the default value is 0) – Two-Bit Alchemist Feb 24 '16 at 20:48
3

You can use collections.defaultdict() which allows you to supply a function that will be called each time a missing key is accessed.

And for your first example you can pass the int to it as the missing function which will be evaluated as 0 at first time that it gets accessed.

And for second one you can pass the list.

Example:

from collections import defaultdict 
my_dict = defaultdict(int)

>>> lst = [1,2,2,2,3] 
>>> for i in lst:
...      my_dict[i]+=1
... 
>>> 
>>> my_dict
defaultdict(<type 'int'>, {1: 1, 2: 3, 3: 1})
>>> my_dict = defaultdict(list)
>>> 
>>> for i,j in enumerate(lst):
...     my_dict[j].append(i)
... 
>>> my_dict
defaultdict(<type 'list'>, {1: [0], 2: [1, 2, 3], 3: [4]})
Mazdak
  • 105,000
  • 18
  • 159
  • 188
1

The best way to do this is with python's excellent in:

myDic = {}
if desiredKey in myDict:
    myDic[desiredKey] += 1
else:
    myDic[desiredKey] = 1
Will
  • 4,299
  • 5
  • 32
  • 50
  • To me this is no different than try/catch. It's just [LBYL instead of EAFP](http://www.oranlooney.com/lbyl-vs-eafp/), where EAFP is [usually preferred](http://stackoverflow.com/a/11360880/2588818) in Python. – Two-Bit Alchemist Feb 24 '16 at 20:49
  • @zondo: Although `get` can be handy it's actually not as efficient as Will's `in`-based approach. In my timeit tests, using `get` is about 40% slower, although that can be reduced to 20% by caching the `get` method. – PM 2Ring Feb 24 '16 at 20:51
  • @Two-BitAlchemist: EAFP is nice, and exceptions in Python are very efficient. However they are significantly slower than the equivalent `if`-based code if the exception is raised, although they are certainly faster when the exception isn't raised. Generally speaking, `try..except` will be faster only if the exception is raised less than 5-10% of the time. – PM 2Ring Feb 24 '16 at 20:54
  • @PM2Ring Sounds like micro-optimization on adding to a dict to me, but my comment was not meant to be about efficiency, just Python's typical style guidelines. – Two-Bit Alchemist Feb 24 '16 at 20:56
  • 1
    @Two-BitAlchemist: Exceptions are great when the condition is actually exceptional, but they are a major performance hit if they are raised too often. If speed is no concern then feel free to always use EAFP. Of course, if speed _is_ a concern, then maybe one should be using a compiled language, not Python. :) – PM 2Ring Feb 24 '16 at 21:03
1

Try this:

myDic = {}
myDic['desiredKey'] = myDic.get('desiredKey', 0) + 1

And similar for your list case:

myDic = {}
myDic['desiredKey'] = myDic.get('desiredKey', []) + [desiredValue]

The .get method for a dict will return the value and default to None instead of throwing an exception. You can also specify the default return value as the second parameter .get(key, default).

olofom
  • 6,233
  • 11
  • 37
  • 50