Python’s KeyError exception is a typical exception encountered by novices. Figuring out why a KeyError will be raised and a few options to forestall it from stopping your program are important steps to enhancing as a Python programmer.

By the top of this tutorial, you’ll know:

  • What a Python KeyError often means
  • The place else you may see a KeyError in the usual library
  • deal with a KeyError once you see it

What a Python KeyError Often Means

A Python KeyError exception is what’s raised once you attempt to entry a key that isn’t in a dictionary (dict).

Python’s official documentation says that the KeyError is raised when a mapping secret is accessed and isn’t discovered within the mapping. A mapping is an information construction that maps one set of values to a different. The most typical mapping in Python is the dictionary.

The Python KeyError is a kind of LookupError exception and denotes that there was a problem retrieving the important thing you had been searching for. If you see a KeyError, the semantic which means is that the important thing being regarded for couldn’t be discovered.

Within the instance under, you’ll be able to see a dictionary (ages) outlined with the ages of three individuals. If you attempt to entry a key that’s not within the dictionary, a KeyError is raised:

>>>

>>> ages = {'Jim': 30, 'Pam': 28, 'Kevin': 33} >>> ages['Michael'] Traceback (most up-to-date name final):   File "<stdin>", line 1, in <module> KeyError: 'Michael' 

Right here, making an attempt to entry the important thing 'Michael' within the ages dictionary ends in a KeyError being raised. On the backside of the traceback, you get the related info:

  • The truth that a KeyError was raised
  • The important thing that couldn’t be discovered, which was 'Michael'

The second-to-last line tells you which ones line raised the exception. This info is extra useful once you execute Python code from a file.

In this system under, you’ll be able to see the ages dictionary outlined once more. This time, you’ll be prompted to supply the identify of the particular person to retrieve the age for:

 1 # ages.py  2   3 ages = {'Jim': 30, 'Pam': 28, 'Kevin': 33}  4 particular person = enter('Get age for: ')  5 print(f'{particular person} is {ages[person]} years previous.') 

This code will take the identify that you just present on the immediate and try to retrieve the age for that particular person. No matter you kind in on the immediate will probably be used as the important thing to the ages dictionary, on line 4.

Repeating the failed instance from above, we get one other traceback, this time with details about the road within the file that the KeyError is raised from:

$ python ages.py Get age for: Michael Traceback (most up-to-date name final): File "ages.py", line 4, in <module>   print(f'{particular person} is {ages[person]} years previous.') KeyError: 'Michael' 

This system fails once you give a key that’s not within the dictionary. Right here, the traceback’s previous few strains level to the issue. File "ages.py", line 4, in <module> tells you which ones line of which file raised the ensuing KeyError exception. Then you’re proven that line. Lastly, the KeyError exception offers the lacking key.

So you’ll be able to see that the KeyError traceback’s remaining line doesn’t offer you sufficient info by itself, however the strains earlier than it will probably get you a large number nearer to understanding what went flawed.

The place Else You Would possibly See a Python KeyError within the Commonplace Library

The big majority of the time, a Python KeyError is raised as a result of a key shouldn’t be present in a dictionary or a dictionary subclass (corresponding to os.environ).

In uncommon instances, you might also see it raised in different places in Python’s Commonplace Library, corresponding to within the zipfile module, if an merchandise shouldn’t be present in a ZIP archive. Nonetheless, these locations hold the identical semantic which means of the Python KeyError, which isn’t discovering the important thing requested.

Within the following instance, you’ll be able to see utilizing the zipfile.ZipFile class to extract details about a ZIP archive utilizing .getinfo():

>>>

>>> from zipfile import ZipFile >>> zip_file = ZipFile('the_zip_file.zip') >>> zip_file.getinfo('one thing') Traceback (most up-to-date name final): File "<stdin>", line 1, in <module> File "/path/to/python/set up/zipfile.py", line 1304, in getinfo   'There isn't any merchandise named %r within the archive' % identify) KeyError: "There isn't any merchandise named 'one thing' within the archive" 

This doesn’t actually seem like a dictionary key lookup. As an alternative, it’s a name to zipfile.ZipFile.getinfo() that raises the exception.

The traceback additionally seems slightly totally different with slightly extra info given than simply the lacking key: KeyError: "There isn't any merchandise named 'one thing' within the archive".

The ultimate factor to notice right here is that the road that raised the KeyError isn’t in your code. It’s within the zipfile code, however earlier strains of the traceback point out which strains in your code prompted the issue.

When You Have to Elevate a Python KeyError in Your Personal Code

There could also be instances when it is smart for you to raise a Python KeyError exception in your personal code. This may be carried out through the use of the elevate key phrase and calling the KeyError exception:

Often, the message could be the lacking key. Nonetheless, as within the case of the zipfile package deal, you would choose to provide a bit extra info to assist the following developer higher perceive what went flawed.

In case you resolve to lift a Python KeyError in your personal code, simply ensure that your use case matches the semantic which means behind the exception. It ought to denote that the important thing being regarded for couldn’t be discovered.

Deal with a Python KeyError When You See It

If you encounter a KeyError, there are a number of customary methods to deal with it. Relying in your use case, a few of these options is perhaps higher than others. The last word objective is to cease sudden KeyError exceptions from being raised.

The Traditional Resolution: .get()

If the KeyError is raised from a failed dictionary key lookup in your personal code, you need to use .get() to return both the worth discovered on the specified key or a default worth.

Very similar to the age retrieval instance from earlier than, the next instance exhibits a greater solution to get the age from the dictionary utilizing the important thing offered on the immediate:

 1 # ages.py  2   3 ages = {'Jim': 30, 'Pam': 28, 'Kevin': 33}  4 particular person = enter('Get age for: ')  5 age = ages.get(particular person)  6   7 if age:  8     print(f'{particular person} is {age} years previous.')  9 else: 10     print(f"{particular person}'s age is unknown.") 

Right here, line 5 exhibits how one can get the age worth from ages utilizing .get(). This can outcome within the age variable having the age worth discovered within the dictionary for the important thing offered or a default worth, None on this case.

This time, you’ll not get a KeyError exception raised due to the usage of the safer .get() methodology to get the age somewhat than making an attempt to entry the important thing immediately:

$ python ages.py Get age for: Michael Michael's age is unknown. 

Within the instance execution above, the KeyError is not raised when a foul secret is offered. The important thing 'Michael' shouldn’t be discovered within the dictionary, however through the use of .get(), we get a None returned somewhat than a raised KeyError.

The age variable will both have the particular person’s age discovered within the dictionary or the default worth (None by default). You may also specify a unique default worth within the .get() name by passing a second argument or the key phrase argument default.

That is line 5 from the instance above with a unique default age specified utilizing .get():

age = ages.get(particular person, default=0) 

Right here, as a substitute of 'Michael' returning None, it could return 0 as a result of the important thing isn’t discovered, and the default worth to return is now 0.

The Uncommon Resolution: Checking for Keys

There are occasions when it’s worthwhile to decide the existence of a key in a dictionary. In these instances, utilizing .get() won’t provide the right info. Getting a None returned from a name to .get() might imply that the important thing wasn’t discovered or that the worth discovered on the key within the dictionary is definitely None.

With a dictionary or dictionary-like object, you need to use the in operator to find out whether or not a secret is within the mapping. This operator will return a boolean (True or False) worth indicating whether or not the secret is discovered within the dictionary.

On this instance, you’re getting a response dictionary from calling an API. This response may need an error key worth outlined within the response, which might point out that the response is in an error state:

 1 # parse_api_response.py  2 ...  3 # Assuming you bought a `response` from calling an API that may  4 # have an error key within the `response` if one thing went flawed  5   6 if 'error' in response:  7     ...  # Parse the error state  8 else:  9     ...  # Parse the success state 

Right here, there’s a distinction in checking to see if the error key exists within the response and getting a default worth from the important thing. This can be a uncommon case the place what you’re truly searching for is that if the secret is within the dictionary and never what the worth at that secret is.

The Basic Resolution: attempt besides

As with every exception, you’ll be able to all the time use the attempt besides block to isolate the potential exception-raising code and supply a backup resolution.

You need to use the attempt besides block in an analogous instance as earlier than, however this time offering a default message to be printed ought to a KeyError be raised within the regular case:

 1 # ages.py  2   3 ages = {'Jim': 30, 'Pam': 28, 'Kevin': 33}  4 particular person = enter('Get age for: ')  5   6 attempt:  7     print(f'{particular person} is {ages[person]} years previous.')  8 besides KeyError:  9     print(f"{particular person}'s age is unknown.") 

Right here, you’ll be able to see the conventional case within the attempt block of printing the particular person’s identify and age. The backup case is within the besides block, the place if a KeyError is raised within the regular case, then the backup case is to print a unique message.

The attempt besides block resolution can also be a fantastic resolution for different locations that may not help .get() or the in operator. It’s also the very best resolution if the KeyError is being raised from one other particular person’s code.

Right here is an instance utilizing the zipfile package deal once more. This time, the attempt besides block provides us a solution to cease the KeyError exception from stopping this system:

>>>

>>> from zipfile import ZipFile >>> zip = ZipFile('the_zip_file.zip') >>> attempt: ...     zip.getinfo('one thing') ... besides KeyError: ...     print('Cannot discover "one thing"') ... Cannot discover "one thing" 

For the reason that ZipFile class doesn’t present .get(), just like the dictionary does, it’s worthwhile to use the attempt besides resolution. On this instance, you don’t should know forward of time what values are legitimate to move to .getinfo().

Conclusion

You now know some frequent locations the place Python’s KeyError exception might be raised and a few nice options you would use to forestall them from stopping your program.

Now, the following time you see a KeyError raised, you’ll know that it’s in all probability only a unhealthy dictionary key lookup. Additionally, you will be capable to discover all the data it’s worthwhile to decide the place the error is coming from by the previous few strains of the traceback.

If the issue is a dictionary key lookup in your personal code, then you’ll be able to swap from accessing the important thing immediately on the dictionary to utilizing the safer .get() methodology with a default return worth. If the issue isn’t coming from your personal code, then utilizing the attempt besides block is your greatest guess for controlling your code’s circulate.

Exceptions don’t should be scary. As soon as you know the way to know the data offered to you of their tracebacks and the basis reason behind the exception, then you need to use these options to make your applications circulate extra predictably.