Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python dictionary keyError

New to python and what looks like simple doable piece of code yielding KeyError:

patt=list('jkasb')

dict={}
for i in patt:
    dict[i]= 1 if dict[i] is None else dict[i]+1 # This line throws error

error: KeyError: 'j'

like image 968
Sachin Verma Avatar asked Sep 16 '25 23:09

Sachin Verma


2 Answers

In your case, the KeyError is occurring because you are trying to access a key which is not in the dictionary. Initially, the dictionary is empty. So, none of the keys exist in it.

This may seem strange if you are coming from a C++ background as C++ maps give default values for keys that don't exist yet. You can get the same behavior in python by using collections.defaultdict. The modified code is given below. I took the liberty of converting the defaultdict to a regular dictionary at the end of the code:

from collections import defaultdict
patt='jkasb'

my_default_dict=defaultdict(int)
for i in patt:
    my_default_dict[i]+=1

my_dict = dict(my_default_dict) # converting the defaultdict to a regular dictionary

You can also solve this problem in a number of other ways. I am showing some of them below:

  • By checking if the key exists in the dictionary:

    patt='jkasb'
    
    my_dict={}
    for i in patt:
        my_dict[i]= 1 if i not in my_dict else my_dict[i]+1 # checking if i exists in dict
    
  • Using dict.get() without default return values:

    patt='jkasb'
    
    my_dict={}
    for i in patt:
        my_dict[i]= 1 if my_dict.get(i) is None else my_dict[i]+1 # using dict.get
    print(my_dict)
    
  • Using dict.get() with default return values:

    patt='jkasb'
    
    my_dict={}
    for i in patt:
        my_dict[i]= my_dict.get(i, 0)+1 # using dict.get with default return value 0
    
  • As your code is actually just counting the frequency of each character, you can also use collections.Counter and then convert it to a dictionary:

    from collections import Counter
    patt='jkasb'
    
    character_counter = Counter(patt)
    
    my_dict = dict(character_counter)
    

Also, as dict is a built-in data type and I used dict to convert the defaultdict and Counter to a normal dictionary, I changed the name of the dictionary from dict to my_dict.

like image 189
Shoumik Hoque Avatar answered Sep 18 '25 16:09

Shoumik Hoque


While building the dict dict, dict[i] is trying to access a key which does not exist yet, in order to check if a key exists in a dictionary, use the in operator instead:

d[i] = 1 if i not in d else d[i] + 1

Alternatives (for what you're trying to accomplish):

Using dict.get:

d[i] = d.get(i, 0) + 1

Using collections.defaultdict:

from collections import defaultdict
d = defaultdict(int)
for i in 'jkasb':
    d[i] += 1

Using collections.Counter:

from collections import Counter
d = Counter('jkasb')

Avoid using dict (built-in type) as a variable name. And just iterate over 'jkasb' without having to convert it to a list, strings are iterable too.

like image 38
MrGeek Avatar answered Sep 18 '25 15:09

MrGeek