o7planning

Python exception handling Tutorial with Examples

  1. What is Exception?
  2. Exception Hierarchy
  3. Handling exception with try-except
  4. try-except-finally
  5. Re-throw exception
  6. Exception Wrapping

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:
Three
Two
One
Error division by zero
Ignore to coninue ...
Let's go!
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
  • Direct subclasses are 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.
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:
Start Recruiting ...
Check you Age 11
You are too young, not pass!
Cause message: Age 11 too young
Invalid age: 11
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)
Output:
Start Recruiting ...
Check you Age 51
You are not pass!
type(e): <class 'ageexceptioon.TooOldException'>
Cause message: Age 51 too old
Invalid age: 51

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 : 
    # The 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:
-- Begin parse text: 001234A2
ValueError message: invalid literal for int() with base 10: '001234A2'
type(e): <class 'ValueError'>
-- End parse text: 001234A2
Value= 0
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")
Output:
Three
Two
One
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.
Syntax
try : 
    # Do Something here... 
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)
Output:
Error message: Nguyen does not pass
e.__cause__: LanguageException('Accept english language only',)
type(cause): <class '__main__.LanguageException'>
 ------------------
Language exception: Accept english language only