A Comprehensive Guide for Understanding Errors and Exception Handling in Python

A Comprehensive Guide for Understanding Errors and Exception Handling in Python

Demystifying Errors and Exception Handling in Python Programming

In this article we'll cover in-depth about errors and exceptions in Python programming. It is most times unavoidable to build or use applications without coming across errors. Python interpreter uses the try....except code block to handle exceptions that may occur during program execution.

💡
Already familiar with Exception Handling or New to Python? Check out the previous comprehensive article on Python Functions titled: A Complete Guide to Python File Handling: Data Manipulation Made Simple in this Python series.

Error

Error is the failure, issues, or problems encountered while developing, debugging or using an an application that causes it not to function properly or as designed. The error could either be a syntax error and exception.

Syntax Error

A syntax error is an error that occurs when there's a violation of the python's coding structure or rule. For example:

def error_log():
    print("error logger for python)

The code above will throw an error because according to syntax rule a string literal must be terminated. There's a ^ symbol pointing where the unterminated string literal is spotted with the line number and the SyntaxError name of the error with the message.

💡
The Understanding Python Syntax: A Comprehensive Guide for Python Programming on this python series has an extensive guide on Python programming syntax.

Exceptions

Exceptions are errors that are detected or that occurs during the execution of a program. There are different types of exception which is usually indicated in the error message. Exception messages can be defined by users (developers). In Python, built-in identifiers are standard exception names which is different from reserved keywords. Here's the basic structure of try...except in Python.

try:
    # code to execute with possibilities of causing exception
except:
    # code to execute if an exception was caught

Examples of built-in Exception error in Python Programming:

FileNotFoundError this exception is caught when a file is not found.

ZeroDivisionError this exception is caught when there's an attempt to divide a number by zero.

ImportError this exception is caught when an imported module is not found.

  • To view all the list of built-in exception in Python
print(dir(locals()['__builtins__']))

List of Python's built-in exceptions can be found here

Exception Handling

Python uses the try...except keywords to handle exceptions.

For example: the code below is correct syntax wise but during execution it'll throw an exception called NameError because it cannot find the error_logg() function in the program.

def error_log():
    print("error logger for python")
error_logg()

Try....Except

try:
    def error_log():
        print("error logger for python")
    error_logg()
except Exception:
    print("This a cleaner way to return exception errors")

The codes between the try and except keyword is executed first. If an exception occurs during the execution it skips to find if the error type matches the exception named after the except keyword. An unhandled exception occurs and execution stops with an error message if no error type | handler is matched after passing it to the outer try statement.

Catching Specific Exceptions in Python

try:
    def error_log():
        print("error logger for python")
    error_logg()
#NameError is a used to catch a specific exception when a name is not found.
except NameError:
    print("This a cleaner way to return exception errors")

To define handlers for different types of exceptions, a try statement may contain more than one except clause. The exception can take in multiple type as a parenthesized tuple, for example:

try:
    def error_log():
        print("error logger for python")
    f = open("users.txt")
except (RuntimeError, TypeError, NameError, FileNotFoundError) as e:
    print(e)
#[Errno 2] No such file or directory: 'users.txt'
  • Example 2

using the parenthesized tuple argument to match the exception type for NameError

try:
    def error_log():
        print("error logger for python")
    f = open("user.txt")
    error_logg()
except (RuntimeError, TypeError, NameError, FileNotFoundError) as e:
    print(e)

#name 'error_logg' is not defined

The Exception keyword is used to specify a general error response. The program stops when it encounters the Exception type as the first specific. It should be defined after the check on the specific type of exception errors.

try:
    def error_log():
        print("error logger for python")
    error_log()

    f =  open('user.txt')
except NameError:
    print("This is an error returned when it matches the NameError exception")
except Exception:
    print("General response when no specific exception clause is matched")

#error logger for python
#General response when no specific exception clause is matched

Displaying the error from the exception

The as e after the except value is used to display the Python exception message in a more readable format.

try:
    def error_log():
        print("error logger for python")
    error_log()
    f =  open('user.txt')
except NameError as e:
    print(e)
except Exception as e:
    print(e)

# error logger for python
#[Errno 2] No such file or directory: 'user.txt'

The error above is more readable compared to the screenshot below:

def error_log():
    print("error logger for python")
error_log()
f =  open('user.txt')

Try...except...Else

The else: execute the the code within it if no error is caught in the try clause or if no exception was thrown.

try:
    def error_log():
        print("error logger for python")
except NameError as e:
    print(e)
except Exception as e:
    print(e)
else:
    error_log()

#error logger for python

Try...except...else...finally

The code in the finally gets executed with or without any exception. The finally runs even If the code between the try and except keyword gets executed or the except throws an error.

  • The code in the finally gets executed even when no exception was caught.
try:
    def error_log():
        print("error logger for python")
except NameError as e:
    print(e)
except Exception as e:
    print(e)
else:
    error_log()
finally:
    print("Something to be done to keep things in order")

#error logger for python
#Something to be done to keep things in order
  • In the example below: the code in the finally gets executed even with the NameError: exception that is thrown.
try:
    def error_log():
        print("error logger for python")
    error_logg()
except NameError as e:
    print(e)
except Exception as e:
    print(e)
else:
    print("A display if the try works fine")
finally:
    print("Something to be done to keep things in order")

# name 'error_logg' is not defined
# Something to be done to keep things in order

Nested try.....except

The try....except can be nested. The code below displays a nested try....except in the else block. If no error was caught in the outer try the code (try....except block) in the else will be executed.

try:
    def error_log():
        print("error logger for python")
    f = open("user.txt")
except (RuntimeError, TypeError, NameError, FileNotFoundError) as e:
    print(e)
else:
    try:
        f = open("users.txt")
        print(f.read())
    except Exception as e:
        print(e)
#[Errno 2] No such file or directory: 'users.txt'

Manually Raising Exception

Exception can be raised within the try...except block. In the example below: an Exception is raised if the file name is the same.

try:
    def error_log():
        print("error logger for python")
    f = open("user.txt")
    if f.name == "user.txt":
        raise Exception("File not found!")
except NameError as e:
    print(e)
except Exception as e:
    print(e)
else:
    print("A display if the try works fine")
finally:
    print("Something to be done to keep things in order")

# File not found!
# Something to be done to keep things in order

Custom (User) - Defined Exception

A user can define a custom exception handler. The exception can be derived from the Exception class directly or indirectly. It's best to define custom exceptions with names ending with Error similar to the standard built-in exceptions. It uses the object oriented programming style.

💡
If you're new to object oriented programming check this article: A Comprehensive Guide to Understanding Object-Oriented Programming (OOP) in Python
  • Returning a custom message through argument
class EmptyError(RuntimeError):  
    # Constructor 
    def __init__(self, value): 
        self.value = value 

    # __str__ is to return the argument value
    def __str__(self): 
        return(repr(self.value)) 

try:  
    var = ""
    raise EmptyError("The variable is empty")  
except (EmptyError) as e:  
    print(e)   

#'The variable is empty'
  • The above code can still be achieved in the format below
class EmptyError(RuntimeError):  
    pass
try:  
    var = ""
    raise EmptyError("The variable is empty")  
except (EmptyError) as e:  
    print(e)   
#The variable is empty
  • For fixed message when defining a custom exception
class EmptyError(RuntimeError):  
    def __init__(self): 
        super().__init__("The variable is not greater than zero!!!")
try:  
    var = 0
    if var > 0:
        print("No exception")
    else:
        raise EmptyError()  
except (EmptyError) as e:  
    print(str(e))   

#The variable is not greater than zero!!!

Look up the Python error documentation for several use cases.

Conclusion

Errors are inevitable when developing or using applications hence the need to understand how best to manage or handle them in Python programming. The try...exception is used to catch and handle errors that occur while executing the program. The try checks for exception and if found the except throws the error. The try..exception..else..finally are the 4 major keywords in use in Python structure for handling exception. The raise statement is used to manually raise an exception. Python's exception handling can be used to display proper and readable messages to non-technical users of an application. It makes code readable, clean and easy to debug.

Find this helpful or resourceful? kindly share with others and feel free to use the comment section for questions, answers, and contributions.

💡
Follow me on Hashnode: Alemsbaja X: Alemsbaja | Youtube: Tech with Alemsbaja to stay updated on more comprehensive articles in Tech.

Did you find this article valuable?

Support Alemoh Rapheal Baja by becoming a sponsor. Any amount is appreciated!