Exception Handling In Python

Introduction

There is a common misunderstanding between errors and exceptions, and most of us think that these two terms are the same. But that’s untrue. These terms are similar but still different concepts.

Error is a bug in the code that causes crooked output or breaks off a program from executing (Refer to my article- https://www.c-sharpcorner.com/article/errors-in-python/) While an Exception is an irregular unforeseen situation occurring during execution on which you do not have any control. So basically, exception is a situation that occurs during run-time.

For example, You write a code that opens a file in read mode and then it displays some content on the screen as an output. The code is correct logically and by syntax too. So, there would be no error while executing it. But take a scenario, where the file that you are trying to open is missing. Now this situation will cause an exception.

There are 2 types of exceptions,

1. Built-in Exceptions

There are plenty of built-in exceptions in Python that are raised when alike errors occur but some of the common exceptions are,

  1. ZeroDivisionError: Occurs when there is division by zero.
  2. NameError: It occurs when a name is not found. It may be local or global.
  3. IndentationError: If incorrect indentation is given.
  4. IOError: It occurs when I/O operations fails.
  5. EOFError: It occurs when there is end of the file is, and still operations are being performed.

To check out other built-in exceptions, just write,

print(dir(locals()['__builtins__']))

You can find details of all the built-in exceptions on the official website, here- https://docs.python.org/3/library/exceptions.html

2. User-Defined Exceptions

  • User-defined exceptions mean customizing exceptions according to your requirement.
  • We create a new exception class in this case but these exceptions need to be derived from the existing or built-in exception classes discussed above.

Example

class MyUserDefinedClass (Exception):
 def __init__(self, value):
 self.value = value
 def __str__(self):
 return(repr(self.value))
try:
 raise(MyUserDefinedClass (3*2))
except MyUserDefinedClass as e:
 print('A New Exception occured: ',e.value)

Output

In the above example, we are creating a new class MyUserDefinedClass which is derived from super class Exception. The value of Exception is stored in ‘e’. We are initializing the value in the constructor; _init_ is the initializer. Then, __str__  is to print() the value. After that we are writing the code inside try block which might throw an exception, so as a precaution we put it inside try block and then except block will handle the exception in case try throws an exception but the execution of the code won't stop in any case.

Exception Handling

Unlike errors, exceptions can be handled before they occur. We have a way to handle the exceptions in python so that the code can be executed without any interruption. Uncaught exceptions will cause the interpreter to halt the execution.

Let’s see an example and figure out what happens if exceptions are not handled,

a = int(input("Enter value of a:"))
b = int(input("Enter value of b:"))
c = a/b
print("a/b = %d" %c) 

Output

The above example throws an exception and the execution of the code will stop here. That's why exception-handling plays an essential role in handling these unexpected exceptions. Exception handling is managed by the following 4 keywords:

  1. Try- The condemnatory portion which can raise an exception is placed inside the try clause
  2. Except- The code that handles the exceptions is written in the except clause.
  3. Else- In some situations, you might want to run a certain block of code if the code block inside try ran without any errors then you use the optional else keyword with the try statement.
  4. Finally- This clause is executed no matter what, and is generally used to release external resources.

Exception handling statements are,

1. try- except

  • If you are doubtful that a particular code snippet would throw an exception then put that inside a try block. In case there is no exception, then code will work normally but if there is an exception then your try block should be followed by an except block.
  • You can catch multiple exceptions at a time, by using multiple except blocks.

SYNTAX

try:
 #codeBlock
except exception1:
 #codeBlock
except exception2:
 #codeBlock

Let’s consider the above example only,

try:
 a = int(input("Enter value of a:"))
 b = int(input("Enter value of b:"))
 c = a/b
 print("a/b = %d" %d)
except(ZeroDivisionError):
 print("Division by Zero not allowed")
except:
 print("Variable not defined")

Output-

As you can see in the above code, first except is handling division by zero exception and hence will print ‘Division by Zero not allowed ‘ whenever there is division by zero and second except block is handling the name error exception because we are trying to print variable ‘d’ which is not defined so instead stopping the execution of the program it will print ‘Variable not defined’

2. try- except- else

  • In previous statement we saw that when there was an exception except block gets executed. What if we want something to happen even if there is no exception? Here comes the role of else block.
  • else block gets executed when:
  • There is no exception
  • No except block is executed.

SYNTAX

try:
 #codeBlock
except exception1:
 #codeBlock
else:
 #codeBlock

Example

try:
 a = int(input("Enter value of a:"))
 b = int(input("Enter value of b:"))
 c = a/b
 print("a/b = %d" %c)
except(ZeroDivisionError):
 print("Divsion by Zero not allowed")
else:
 print("Yay! There was no exception.")

Output

3. try-finally

  • Adding a keyword to the statement- finally. finally is always executed no matter what. Now you must be wondering that what is the difference between else and finally.
  • You can also use finally with except and else.
  • Major difference between else and finally is that finally is executed regardless of whether the statements in the try block fail or succeed. else is executed only if the statements in the try block don't raise an exception.
  • Finally is generally used to,
    • Release external resources
    • Guarantee the execution

SYNTAX

try:
 #codeBlock
finally:
 #codeBlock

Example

try:
 a = int(input("Enter value of a:"))
 b = int(input("Enter value of b:"))
 c = a/b
except ZeroDivisionError:
 print("You are dividing by zero ")
else:
 print("Your answer is :", c)
finally:
 print('This is always executed')

Output

Summary

In this article, we learned about exceptions, their types, and how they are handled along with examples. We saw different ways of handling exceptions using various python keywords. Now we are aware that what is the difference between error and exceptions. For errors, you can refer to my previous article (https://www.c-sharpcorner.com/article/errors-in-python/) and this article will clear up your doubts about exceptions and hence we will know about the relationship and the difference between the two.