Sachin Verma
Sachin Verma

Reputation: 3802

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'

Upvotes: 4

Views: 8474

Answers (5)

Djaouad
Djaouad

Reputation: 22776

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.

Upvotes: 6

Shoumik Hoque
Shoumik Hoque

Reputation: 142

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.

Upvotes: 11

kederrac
kederrac

Reputation: 17322

you are trying to access a key in an empty dictionary, you can also use defaultdic so you do not care if the key exists already or not:

from collections import defaultdict

patt=list('jkasb')

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

Upvotes: 0

Delgan
Delgan

Reputation: 19617

As your dict is initially empty, trying to access any value with dict[i] will throw a KeyError.

You should replace this with .get() which returns None if the key is not found:

for i in patt:
    dict[i] = 1 if dict.get(i) is None else dict[i] + 1

Another alternative, as suggested by @snakecharmerb, is to check beforehand whether or not the key exists in your dict:

for i in patt:
    dict[i] = 1 if i not in dict else dict[i] + 1

Both solutions are equivalent, but the second is maybe more "idiomatic".

Upvotes: 3

Paul M.
Paul M.

Reputation: 10799

These snippets: dict[i] anddict[i]+1 will try to get a value from the dictionary with the corresponding key i. Since you have nothing in your dictionary, you get a KeyError.

Upvotes: 0

Related Questions