4

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'

2
  • 2
    if dict[i] is None raises an error because there is no dict[i] yet. Commented Sep 1, 2019 at 15:48
  • 1
    Also, don't give your variables the name of builtin functions (like dict, here) Commented Sep 1, 2019 at 15:48

5 Answers 5

11

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.

Sign up to request clarification or add additional context in comments.

Comments

6

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.

Comments

3

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

2 Comments

or simply dict[i] = dict.get(i, 0) + 1
got it. Dint know they made dict[] and dict.get to have different behaviour.
0

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.

Comments

0

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 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.