TLDR
try/except
blocks makes sure that your program continues running rather than ending abruptly. By including a except KeyError
, we are specifically making sure that the program does not end abruptly if a KeyError
occurs. result_dict[value] += 1
will throw an error if value
is not a key in the dictionary, because it tries to do access a key that does not exist. The +=
makes the code run similarly to:
result_dict[value] = result_dict[value] + 1
and since value
is not in result_dict, it is similar to saying
result_dict[value] = None + 1
which is bad.
The Non-TLDR version
When an error occurs in python, the program usually terminates abruptly and exits. It does not run any code that occurs below the part where the exception occurs. For example, take the following code. It takes 2 numbers from the user a
and b
, and it will output a/b
a = int(input("Enter a value for a: "))
b = int(input("Enter a value for b: "))
print("a/b is:", a/b)
If the user gives a valid input (say a=4, b=2
) the program proceeds smoothly. However if the user were to give, say a = "c"
, then the following happens
Traceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'c'
And the program ends abruptly. It is perfectly valid to have the program end like that, but rarely do you want the program to end abruptly. Take the case where the user has 1000 inputs, and the last one messes up. The user will then have to restart the program and re-input all 1000 inputs again, because the program ended abruptly.
So now we introduce a try/except
block. We know that converting a non-numeric character into an integer will throw a ValueError
as seen in the error, so we will handle them accordingly
while True:
try:
a = int(input("Enter a value for a: "))
break
except:
print("An error has occurred. Please input a again")
while True:
try:
b = int(input("Enter a value for b: "))
break
except:
print("An error has occurred. Please input b again")
print("a/b is:", a/b)
So now, we take an input from the user, try to convert it into an integer and put that value into a
. If it succeeds, it will proceed smoothly to the next line (break
) and exit the loop. If it fails, then an exception will occur, and it will enter the except
block, where it will print a helpful error message, and run the loop again (until the user enters a valid input). Now the program doesn't just terminate abruptly when it fails. It gives appropriate feedback to the user, and lets the user retry the input again.
That is a general exception block, where you just catch any exception.
But let's now say that there are multiple possible errors that could occur. Take the following code:
a = input()
b = input()
print(int(a)/int(b))
print("I am done")
Now a few errors can occur. One of them is the ValueError
stated above, where the input given cannot be converted into an integer. The other error, is a ZeroDivisionError
where b=0
. Python doesn't like dividing by zero, hence it will throw an exception and terminate the program immediately.
So now, you want to print a special message for each type of program. How you do that is by catching specific exceptions
a = input("Enter a value for a: ")
b = input("Enter a value for b: ")
try:
print(int(a)/int(b))
except ValueError:
print("We cannot convert a non-numeric character to an integer")
except ZeroDivisionError:
print("We cannot divide by 0")
except:
print("Some unexpected error has occurred")
print("I am done")
If python was unable to convert the input into an integer, it will enter the ValueError
block of the code, and print "We cannot convert a non-numeric character to an integer"
If python tried to divide by 0, then it will enter the ZeroDivisionError
block and print "We cannot divide by 0"
If any other type of error occurred, it will end up in the final except block and print "Some unexpected error has occurred"
And after the exception is handled, it prints "I am done"
Note that if the final except
block was not there to catch any other exceptions, then the program will not terminate nicely because the exception was unhandled, and it will not print the final statement.
Now, how does one realise what possible error can occur? That is up to practice, and once you get familiar with the errors, you can handle them accordingly. Or, purposefully make your program throw exceptions, and read the stack trace for what kind of exceptions occur. And then handle them accordingly. You don't have to handle each specific error differently, you could handle all of them in the same way.
You can read more here: Python's documentation for errors and exceptions