• Oct 31, 2024

Exceptions in Python

  • DevTechie

In Python, exceptions represent run time logical errors. Exception handling in Python is crucial for gracefully handling errors and preventing program crashes.

Background

In Python, exceptions represent run time logical errors. Exception handling in Python is crucial for gracefully handling errors and preventing program crashes.

If you are ‌new to the concept of exceptions and exception handling, let’s quickly understand them before this article explains how to raise exceptions via your code/program. In a normal program flow, exceptions are raised by Python runtime environment/interpreter.

What is an exception?

  • In Python, an exception is an event that occurs during the execution of a program, disrupting the normal execution flow.

  • Exceptions can be caused by various factors, such as invalid input, division by zero, or accessing nonexistent elements.

  • Unlike syntax errors (which lead to program termination), exceptions allow the program to continue running, albeit with altered behavior.

Exception Object — Python Representation of Exception

  • Like everything, an exception is also represented as an object programmatically.

  • An exception is an object derived from the BaseException class.

  • It contains information about an error event that occurred within the code.

The exception object includes:

1 — Error type (exception name)

2 — The state of the program when the error occurred

3 — An error message describing the event

Exception handling

Catching and responding to exceptions gracefully by the apps is called Exception handling. In Python, exception handling is accomplished with the aid of try … except construct. The try … except can also include optional else and finally clauses.

Here is a quick recap of these blocks of exception handling:

try Block:

  • The try block contains ‌code that might raise an exception.

  • It’s where you test risky code.

  • If an exception occurs within the try block, the remaining code inside it is skipped.

except Block:

  • The except block handles the error raised in the try block.

  • When an exception occurs, the program jumps to the corresponding except block.

  • You can specify the type of exception you want to catch (e.g. ZeroDivisionError, ValueError, etc.).

else Block:

  • The else block executes code when there is no error.

  • It runs only if no exception was raised in the try block.

finally Block:

  • The finally block always executes, regardless of whether an exception occurred or not.

  • It’s useful for cleanup tasks (e.g., closing files, releasing resources).

Here’s the basic structure for exception handling:

try:
    # Code that may cause an exception
    
except exception-name:
    # Handle exception named exception-name
   
else:
    # Code to run when no exception occurs in the try block
finally:
    # (always executed)
    # Most often contains cleanup code, used in resource management

Raising exceptions via the code

Python also allows you to raise an exception programmatically. That is, you can force an exception to occur. In Python this is accomplished using the raise statement. In Java, the throw statement is used for the same purpose.

The raise statement lets the programmer force a specific exception to occur. The raise statement is useful when you need to signal an exception to the caller (program). You can raise exceptions in circumstances where data is incorrectly received, or data validation fails.

The only argument in the raise statement specifies the exception to be raised. This must be an object of Exception or any derived class of Exception.

Most built-in exceptions are derived from Exception which is itself ‌a derived class (subclass) of BaseException.

Procedure to raise an exception is as follows: 
 
1 — Make an exception of the proper type. Use the built-in exceptions or as a developer, you can create your own exceptions based on the requirements.

This article discusses only raising built-in exceptions. The syntax and steps to raise custom exceptions are likewise. In a different article, I will talk about defining custom exceptions.

2 — Pass the required data/value when raising an exception i.e. create an instance of the appropriate exception class.

3 — Execute the raise statement command by specifying the exception class.

The syntax to use the raise statement is as shown below:

raise Exception_class (<value>)

Example

Example 1:

Let’s consider the below code which raises an exception via the raise​statement.

marks = int (input the marks: "))
if (marks > 100):
    raise ValueError("Marks can not be more than 100. Max marks is 100")
else:
    print ("Your input is accepted")

Outputs: Outputs of the above code with different inputs are as under:

Enter the marks: 45
Your input is accepted
Enter the marks: 100
Your input is accepted
Enter the marks: 101
ERROR!
Traceback (most recent call last):
  File "<string>", line 3, in <module>
ValueError: Marks can not be more than 100. Max marks is 100

The above program only raises an error via code. The code raises a built-in exception ValueError. You can also catch and handle this exception using try … except ​construct as shown in the below code:

try:
    marks = int (input the marks: "))
    if (marks > 100):
        raise ValueError("Marks can not be more than 100. Max marks is 100")
    else:
        print ("Your input is accepted")
except ValueError as e:
    print(" You provided invalid value.")
    print (f"Here are the details: {e}")

Output:

Enter the marks: 101
 You provided invalid value.
Here are the details: Marks can not be more than 100. Max marks is 100

Example 2:

You can raise any type of exception. For example, the below raises TypeError, it the marks is not an integer value.

try:
    marks = eval( input ( "Enter the marks: ")) 
    if (not isinstance (marks, int)):
        raise TypeError("Only integers are allowed.")
    else:
        print ("Your input is accepted")
        
except TypeError:
    print(" You provided invalid value. Please provide an integer value since marks can not be fractional")

In Python, the eval() function is a powerful tool that allows you to dynamically evaluate Python expressions or statements stored as strings. In the above code, eval() function changes the value from console string input to a numeric value.

Outputs:

Enter the marks: 45
Your input is accepted
Enter the marks: 45.6
 You provided invalid value. Please provide an integer value since marks can not be fractional

Example 3:

A complete program may raise multiple exceptions as and when required. The below code raises both ValueError and TypeError.

try:
    marks = eval( input ( "Enter the marks: ")) 
    if (not isinstance (marks, int)):
        raise TypeError("Only integers are allowed.")
    elif (marks > 100):
        raise ValueError("Marks can not be more than 100. Max marks is 100")
    else:
        print ("Your input is accepted")
    
except ValueError as e:
    print(" You provided invalid value.")
    print (f"Here are the details: {e}")
        
except TypeError:
    print(" You provided invalid value. Please provide an integer value since marks can not be fractional")

Output:

Enter the marks: 89
Your input is accepted
Enter the marks: 101
 You provided invalid value.
Here are the details: Marks can not be more than 100. Max marks is 100
Enter the marks: 89.5
 You provided invalid value. Please provide an integer value since marks can not be fractional

Recapitulate

Proper exception handling ensures robust and reliable Python programs. This article talks about raising exceptions explicitly to develop robust programs.