Manually Raising (throwing) an Exception in Python

Problem Statement: How to raise (throw) an exception in Python manually?

Using raise to Throw Exception in Python

You can decide to throw a specific exception manually if a particular condition arises with the help of the raise keyword. As a good practice, you should raise specific exceptions. In the following example, we will raise a ZeroDivisionError using the raise keyword.

Example:

x = 5
while True:
    print(x)
    print("Result:",20/x)
    x-=1
    if x == 0:
        raise ZeroDivisionError('Cannot Divide by Zero!')
        break

Output:

Traceback (most recent call last):
  File "C:\Users\SHUBHAM SAYON\PycharmProjects\Finxter\General\Manual_exception.py", line 7, in <module>
    raise ZeroDivisionError('Cannot Divide by Zero!')
ZeroDivisionError: Cannot Divide by Zero!

Raising Multiple Exceptions in Python

One way to deal with multiple errors and raise them manually is to use the try and except blocks judiciously within your code. In the following code, we will see how more than one error can be raised using try and catch clauses within function definitions and then raise the errors finally.

import sys
err = []
line = []
try:
    def foo():
        x = 2
        try:
            while x > -1:
                y = 4 / x
                print(f'y = {y}')
                x -= 1
        except ZeroDivisionError as e:
                err.append(e)
                exception_type, exception_object, exception_traceback = sys.exc_info()
                line_number = exception_traceback.tb_lineno
                line.append(line_number)
                foo_1()

    def foo_1():
        x = "12345"
        for i in x:
            print(f'i = {i}')
        try:
            print(x / 2)
        except Exception as e:
            err.append(e)
            exception_type, exception_object, exception_traceback = sys.exc_info()
            line_number = exception_traceback.tb_lineno
            line.append(line_number)

except:
    print("Something Happened!")


foo()

if err:
    raise Exception(err, line) 

Output:

Traceback (most recent call last):
  File "C:\Users\SHUBHAM SAYON\PycharmProjects\Finxter\General\Manual_exception.py", line 38, in <module>
    raise Exception(err, line)
Exception: ([ZeroDivisionError('division by zero'), TypeError("unsupported operand type(s) for /: 'str' and 'int'")], [9, 24])
y = 2.0
y = 4.0
i = 1
i = 2
i = 3
i = 4
i = 5

Process finished with exit code 1

Explanation:

  • Catch the respective errors within the except blocks of the respective functions and then append them to their name and the line of their occurrence within different lists.
  • Since each list stores the individual error name and the line of occurrence of the error, we use the raise keyword to throw the errors in the final section of our code.

🚫Don’t Raise Generic Exceptions

πŸ‘Thumb rule: You should not try to raise/throw a generic exception,i.e., do not raise any exception that is not specific. This refers to the Exception class, which is at the top of the hierarchy.

Here’s the exception class tree in case you want to visualize it:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- EncodingWarning
           +-- ResourceWarning

Thus, in case you want to raise an exception manually, then make it a habit to raise a specific exception so that you can easily catch it later in your code. In case you raise a generic exception and later try to handle it with the help of a specific exception, you will get an error since the Exception class will not be able to handle a more specific exception.

Example:

try:
  raise Exception('The Generic exceptions will be not caught and defeat the purpose!')
except NameError as e :
  print("Variable x is not defined")

Output:

Traceback (most recent call last):
  File "./prog.py", line 2, in <module>
Exception: The Generic exceptions will be not caught and defeat the purpose!

Retrieve the Name, Type and Line Number of an Exception

To retrieve the information of an exception, you can use the sys.exec_info() method. sys.exc_info() is used to get the file, line number and type of exception raised. It returns  a tuple containing the exception type, the exception object, and the exception traceback.

Example:

import os.path
import sys
try:
    raise NotImplementedError("Type: Not Implemented Error!")
except Exception as e:
    type_excptn, obj, trace_bk = sys.exc_info()
    name = trace_bk.tb_frame.f_code.co_filename
    line = trace_bk.tb_lineno
    print("Exception type: ", type_excptn)
    print("File name: ", str(name))
    print("Line number: ", line)

Output:

Exception type:  <class 'NotImplementedError'>
File name:  C:\Users\SHUBHAM SAYON\PycharmProjects\Finxter\General\Manual_exception.py
Line number:  4

Raise and Log an Exception

It is a good practice to log the exceptions in a report. Hence, we will have a look at how to log a raised exception in Python.

Approach: Raise the exception and log it into another file, as shown below.

Example:

try:
    raise ValueError("This ValueError will be logged!")
except ValueError as err:
    f = open("log.txt", "a")
    f.write(str(err))
    f.close()

Output:

Conclusion

To sum things up, you can use the raise keyword to manually raise an exception. We also learned how to raise and manage multiple exceptions and how to retrieve information about an exception. I hope this article has helped you.

Please stay tuned and subscribe for more interesting articles and discussions. Happy learning!


To become a PyCharm master, check out our full course on the Finxter Computer Science Academy available for free for all Finxter Premium Members:

πŸ§‘β€πŸ’» Recommended: Python Print Exception: 13 Easy Ways to Try-Except-Print Errors for Beginners