Reputation: 3802
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
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):
dict.get
:d[i] = d.get(i, 0) + 1
collections.defaultdict
:from collections import defaultdict
d = defaultdict(int)
for i in 'jkasb':
d[i] += 1
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
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
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
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
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