Python exception handling Tutorial

1- What is Exception?

First, let's see the following illustration example:
In this example, there is an part of error code which results from the division by 0. The division by 0 causes the exception:  ZeroDivisionError
helloExceptionExample.py

print ("Three")

# This division no problem.
value = 10 / 2

print ("Two")

# This division no problem.
value = 10 / 1

print ("One")

d = 0

# This division has problem, divided by 0.
# An error has occurred here.
value = 10 / d;

# And the following code will not be executed.
print ("Let's go!");

 
The result from running the example:
You can see the notification on the Console screen. The error notification is very clear, including the information of code line.
Let see the flow of the program through the following illustration:
  • The program runs normally from step (1), (2) to (6).
  • In step (7), the program divided by 0. Program ends.
  • And step (8), code has not been executed.

We will modify code of above example.

helloCatchException.py

print ("Three")

value = 10 / 2

print ("Two")

value = 10 / 1
 
print ("One")

d = 0


try :
    # This division has problem, divided by 0.
    # An error has occurred here (ZeroDivisionError).
    value = 10 / d;
    
    print ("value = ", value)
    
except ZeroDivisionError as e :
    
    print ("Error: ", str(e) )
    print ("Ignore to continue ...")


print ("Let's go!");
 
And the results of running the example:
We will explain the flow of the program by the following illustration images.
  • Steps (1) to (6) are completely normal.
  • Exception occurs in step (7), the problem divided by zero.
  • Immediately it jumps in executing the command in catch block, step (8) is skipped.
  • Step (9), (10) is executed.
  • Step (11) is executed.

2- Exception Hierarchy

This is the model of hierarchical map of Exception in Python.
  • The highest class is BaseException
  • Two direct subclasses is Exception and KeyboardInterrupt.
The Exception which is builtin of  CSharp is usually derived from BaseException. Meanwhile, the programmers' Exception should inherit from Exception or its subclasses.

3- Handling exception with try-except

We write a class that inherits from Exception.
See more:
The checkAge function to check the age, if the age is less than 18 or greater than 40, an exception will be thrown.
ageexception.py
# Python 3.x

class AgeException(Exception):
    
    def __init__(self, msg, age ):
        super().__init__(msg)
        self.age = age
        
        
class TooYoungException(AgeException):
    
    def __init__(self, msg, age):
        super().__init__(msg, age)    
        

class TooOldException(AgeException):
    
    def __init__(self, msg, age):
        super().__init__(msg, age)    
        

# Function to check age, it may raise exception.
def checkAge(age):

    if (age < 18) :
    
        # If age is less than 18, an exception will be thrown
        # This function ends here.
        raise TooYoungException("Age " + str(age) + " too young", age)
    
    elif (age > 40) :
    
        # If age greater than 40, an exception will be thrown.
        # This function ends here.  
        raise TooOldException("Age " +  str(age) + " too old", age);
  
    # If age is between 18-40.
    # This code will be execute.
    print ("Age " +  str(age) + " OK!");
Example:
tryExceptDemo1.py
import ageexception
from ageexception import AgeException
from ageexception import TooYoungException
from ageexception import TooOldException


print ("Start Recruiting ...")

age = 11

        
print ("Check your Age ", age)

try :


    ageexception.checkAge(age)

    print ("You pass!")

 
except TooYoungException as e  :


    print("You are too young, not pass!")    
    print("Cause message: ", str(e) )
    print("Invalid age: ", e.age)


except  TooOldException as e :

 
    print ("You are too old, not pass!")
    print ("Cause message: ", str(e) )
    print("Invalid age: ", e.age)
   
 
Run the example:
In the following example, we will catch exceptions through parent exceptions.
tryExceptDemo2.py
import ageexception
from ageexception import AgeException
from ageexception import TooYoungException
from ageexception import TooOldException


print ("Start Recruiting ...")

age = 51

      
print ("Check your Age ", age)

try :


    ageexception.checkAge(age)

    print ("You pass!")


except AgeException as e  :


    print("You are not pass!")  
    print("type(e): ", type(e) )
    print("Cause message: ", str(e) )
    print("Invalid age: ", e.age)
 
Running the example:

4- try-except-finally

We have got accustomed with catching error through try-except block. try-except-finally is used to fully handle exception. The finally block is always executed, regardless of whether the exception occurs in the try block or not.
try - except - finally
try :

    # Do something here

except Exception1 as e :

    # Do something here
    

except Exception2 as e :

    # Do something here

finally :

    # Finally block is always executed
    # Do something here
Example:
tryExceptFinallyDemo.py


def toInteger(text) :
      
    try :
  

        print ("-- Begin parse text: ", text)

        # An Exception can throw here (ValueError).
        value = int(text)

        return value

    except ValueError as e :
    
        # In the case of 'text' is not a number.
        # This 'except' block will be executed.  
        print ("ValueError message: ", str(e))
        print ("type(e): ", type(e))

        # Returns 0 if ValueError occurs
        return 0

    
    finally :
  

        print ("-- End parse text: " + text)

  

text = "001234A2"

value = toInteger(text)

print ("Value= ", value)
Running the example:
This is the flow of the program. Finally block is always executed.

pass Statement

If you do not want to process anything in the 'except' or 'finally' block you can use the 'pass' statement. The pass statement does not do anything, it's like a null statement.
passStatementExample.py

print ("Three")

try :
   
    value = 10 / 0;
   
except Exception as e:
   
    pass

print ("Two")   

print ("One")

print ("Let's go")

5- Re-throw exception

While handling the exception, you can catch that exception and handle it or you can re-throw it.
reRaiseExceptionDemo1.py


def checkScore(score) :
    
    if score < 0 or score > 100:
        raise Exception("Invalid Score " + str(score) )
    


def checkPlayer(name, score):
    
    try :
        
        checkScore(score)
     
    except Exception as e :
        
        print ("Something invalid with player: ",name, ' >> ', str(e) )
        
        # re throw exception.
        raise    
 
 
# ------------------------------------------


checkPlayer("Tran", 101)          
For example, catch an exception and throw an other exception.
reRaiseExceptionDemo2.py


def checkScore(score) :
  
    if score < 0 or score > 100:
        raise Exception("Invalid Score " + str(score) )
  


def checkPlayer(name, score):
  
    try :
      
        checkScore(score)
    
    except Exception as e :
      
        print ("Something invalid with player: ",name, ' >> ', str(e) )
      
        # throw new exception.
        raise Exception("Something invalid with player: "+ name + " >> "+ str(e))  


# ------------------------------------------


checkPlayer("Tran", 101)          

6- Exception Wrapping

Python allows catching exceptions, and throws a new exception. New exceptions can store information of the original exception, which you can access through the __cause__ attribute.
try :

    # Do Something ...

except Exception as e :

    raise OtherException("Message...") from e
See full example:
wrapExceptionDemo.py
# Python 3.x:

# Gender exception
class GenderException(Exception):
    
    def __init__(self, msg):
        super().__init__(msg)    

# Language exception
class LanguageException(Exception):
    
    def __init__(self, msg):
        super().__init__(msg)    


class PersonException(Exception):
    
    def __init__(self, msg):
        super().__init__(msg)

# This function may throw GenderException
def checkGender(gender):
    
    if gender != 'Female' :
        raise GenderException("Accept female only")

# This function may throw LanguageException
def checkLanguage(language):  
      
    if language != 'English' :
        raise LanguageException("Accept english language only")
    

def checkPerson(name, gender, language):
    
    try :
        # May throw GenderException
        checkGender(gender)
        # May throw LanguageException    
        checkLanguage(language)
    except Exception as e:
        # Catch exception and raise other exception.
        # New exception has __cause__ = e.
        raise PersonException(name + " does not pass") from e
    
# --------------------------------------------------------


try  :
    
    checkPerson("Nguyen", "Female", "Vietnamese")
    
except PersonException as e:
    
    print ("Error message: ", str(e) )  
    
    # GenderException or LanguageException
    cause = e.__cause__  
    
    print ('e.__cause__: ', repr(cause))
    
    print ("type(cause): " , type(cause) )
    
    print (" ------------------ ")
    
    if type(cause) is GenderException :
        
        print ("Gender exception: ", cause)
        
    elif type(cause) is LanguageException:
        
        print ("Language exception: ", cause)