Exception Handling
Exception handling in Python is a mechanism to manage runtime errors, allowing a program
to respond to unexpected events without crashing. It follows the EAFP (Easier to Ask
Forgiveness than Permission) philosophy, which favours attempting an operation and handling
the failure over complex pre-check logic.
Difference Between Errors and Exceptions
Errors and exceptions are both issues in a program, but they differ in severity and handling.
• Error: Issues in the program logic such as SyntaxError, etc. It occurs at compile time.
• Exception: Problems that occur at runtime and can be managed using exception
handling (e.g., invalid input, missing files).
# Syntax Error (Error)
print("Hello world" # Missing closing parenthesis
# ZeroDivisionError (Exception)
n = 10
res = n / 0
try-except-else-finally
Python uses a structured try...except block to handle potential errors:
Syntax of Exception Handling
Python provides four main keywords for handling exceptions: try, except, else and finally each
plays a unique role. Let's see syntax:
try:
# Code
except SomeException:
# Code
else:
# Code
finally:
# Code
• try: Runs the risky code that might cause an error.
• except: Catches and handles the error if one occurs.
• else: Executes only if no exception occurs in try.
• finally: Runs regardless of what happens useful for cleanup tasks like closing files.
Example: This code attempts division and handles errors gracefully using try-except-else-
finally.
try:
n=0
res = 100 / n
except ZeroDivisionError:
print("You can't divide by zero!")
except ValueError:
print("Enter a valid number!")
else:
print("Result is", res)
finally:
print("Execution complete.")
Output:
You can't divide by zero!
Execution complete.
try block attempts division, except blocks catch specific errors, else block executes only if no
errors occur, while finally block always runs, signaling end of execution.
Common Built-in Exceptions
The Python standard library includes several built-in exception types to categorize different
errors:
• ZeroDivisionError: Raised when dividing by zero.
n = 10
try:
res = n / 0
except ZeroDivisionError:
print("Can't be divided by zero!")
Dividing a number by 0 raises a ZeroDivisionError. The try block contains code that may
fail and except block catches the error, printing a safe message instead of stopping the
program.
• ValueError: Occurs when a function receives an argument of inappropriate value.
try:
# This will cause ValueError
x = int("str")
inv = 1 / x # Inverse calculation
except ValueError:
print("Not Valid!")
except ZeroDivisionError:
print("Zero has no inverse!")
Output
Not Valid!
• TypeError: Raised when an operation is applied to an object of an incorrect type.
• FileNotFoundError: Triggered when attempting to open a file that does not exist.
• IndexError: Occurs when trying to access a list index that is out of range.
Advanced Techniques
• Catching Multiple Exceptions: You can handle multiple exceptions in one block by
using a tuple:
o except (ValueError, TypeError):
Example:
a = ["10", "twenty", 30]
try:
# 'twenty' cannot be converted to int
total = int(a[0]) + int(a[1])
except (ValueError, TypeError) as e:
print("Error", e)
except IndexError:
print("Index out of range.")
Output
Error invalid literal for int() with base 10: 'twenty'
The ValueError is raised when trying to convert "twenty" to an integer. A TypeError could occur
if incompatible types were used, while IndexError would trigger if the list index was out of
range.
• Raising Exceptions: Use the raise keyword to manually trigger an exception when a
specific condition is met.
We raise an exception in Python using the raise keyword followed by an instance of
the exception class that we want to trigger. We can choose from built-in exceptions or
define our own custom exceptions by inheriting from Python's built-in Exception class.
Basic Syntax:
raise ExceptionType("Error message")
Example:
def set(age):
if age < 0:
raise ValueError("Age cannot be negative.")
print(f"Age set to {age}")
try:
set(-5)
except ValueError as e:
print(e)
Output
Age cannot be negative.
The function checks if age is invalid. If it is, it raises a ValueError. This prevents invalid states
from entering the program.
• Custom Exceptions: You can define your own error types by creating a class that
inherits from the base Exception class.
class MyCustomError(Exception):
def __init__(self, message, error_code):
super().__init__(message)
self.error_code = error_code
def __str__(self):
return f"{[Link]} (Error Code: {self.error_code})"
Raising a Custom Exception
To raise a custom exception, use the raise keyword followed by an instance of your custom
exception.
def divide(a, b):
if b == 0:
raise MyCustomError("Division by zero is not allowed", 400)
return a / b
Here the divide method raises the 'MyCustomError' when an attempt to divide by zero is
made.
Handling Custom Exceptions
Custom exceptions can be handled similar to built-in exceptions using a `try...except` block.
try:
result = divide(10, 0)
except MyCustomError as e:
print(f"Caught an error: {e}")
Here divide function raises `MyCustomError` and it is caught and handled by the `except`
block. Additional attributes and methods can be used to enhance Custom Exceptions to
provide more context or functionality.