Exception Handling in Python
Exception Handling in Python
1. What is an Error?
In programming, an error refers to any unexpected or undesired behavior
that occurs during the execution of a program. Errors can occur for various
reasons, and they are generally classified into two main types:
a. Syntax Errors:
Syntax errors, also known as parsing errors, occur when the code violates
the programming language's syntax rules. The interpreter or compiler detects
these errors during the parsing phase before the program is executed. Syntax
errors prevent the program from running and must be fixed before executing the
code.
Example of Syntax Error:
# Syntax Error: Missing colon
if x > 0
print("Positive")
In this example, a syntax error is raised because the if statement is missing a
colon at the end.
2. What is an Exception?
An exception is a Python object that represents an error or an exceptional
condition that occurs during the execution of a program. When an error occurs,
instead of the program terminating abruptly, an exception is raised. This allows
the program to respond to the error in a controlled and graceful manner.
Key Points about Exceptions:
I. Object Representation:
• Exceptions in Python are represented as objects. Each type of
exception is an instance of a specific class derived from the built-in
BaseException class.
II. Triggering Exceptions:
• Exceptions are triggered when an error occurs during the execution
of a program. This can be due to various reasons, such as invalid
input, file not found, division by zero, etc.
III. Exception Handling:
• Python provides a mechanism to handle exceptions using try,
except, else, and finally blocks. This allows you to write code that
gracefully responds to errors without abruptly terminating the
program.
IV. Built-in Exception Types:
• Python has a variety of built-in exception types, such as TypeError,
ValueError, ZeroDivisionError, etc. Each type corresponds to a
specific category of errors.
Example.
try:
# Code that may raise an exception
result = 10 / 0 # Division by zero
except ZeroDivisionError as e:
# Code to handle the exception
print(f"Exception: {e}")
In this example, a ZeroDivisionError exception is raised because the program
attempts to divide by zero. The except block catches the exception, and the
provided code inside the block handles the exceptional condition by printing a
custom message.
3. Types of Exceptions
In Python, exceptions are events that occur during the execution of a
program that disrupts the normal flow of instructions. Python provides a variety
of built-in exceptions to handle different types of errors. Here are some common
types of exceptions in Python:
1. SyntaxError:
- Raised when there is a syntax error in the code, typically a typo or a mistake
in the language structure.
if x = 5:
print("This will result in a SyntaxError.")
2. IndentationError:
- Raised when there is an incorrect indentation in the code.
def my_function():
print("Indented incorrectly.")
3. NameError:
- Raised when a local or global name is not found.
print(variable_that_does_not_exist)
4. TypeError:
- Raised when an operation or function is applied to an object of an
inappropriate type.
5. ValueError:
- Raised when a built-in operation or function receives an argument with the
right type but an inappropriate value.
6. ZeroDivisionError:
- Raised when division or modulo by zero occurs.
7. FileNotFoundError:
- Raised when a file or directory is requested but cannot be found.
with open("nonexistent_file.txt", "r") as file:
# This will result in a FileNotFoundError.
8. IndexError:
- Raised when a sequence subscript is out of range.
my_list = [1, 2, 3]
element = my_list[10] # This will result in an IndexError.
9. KeyError:
- Raised when a dictionary key is not found.
5. try-except block:
The try and except blocks in Python form the core of exception handling.
These blocks allow you to write code that gracefully manages and responds to
potential errors during the execution of a program.
Basic Syntax:
try:
# Code that may raise an exception
# ...
except ExceptionType as e:
# Code to handle the exception
# ...
Key Components:
1. try Block:
- The try block contains the code that might raise an exception. If an exception
occurs within this block, the control is transferred to the corresponding except
block.
2. except Block:
- The except block contains the code to handle the exception. It specifies the
type of exception (or multiple types) that it can catch. If an exception of the
specified type occurs in the try block, the code in the corresponding except
block is executed.
Example:
python
try:
# Code that may raise an exception
result = 10 / 0 # Division by zero
except ZeroDivisionError as e:
# Code to handle the exception
print(f"Exception: {e}")
In this example, the try block attempts to perform a division by zero, which
raises a ZeroDivisionError. The corresponding except block catches this specific
exception type and executes the code inside, printing a custom message.
In Python, you can use a more generic except block to catch exceptions of the
base Exception class. While it is generally recommended to handle specific
exceptions whenever possible, using a generic except block allows you to catch
any exception that inherits from the Exception class.
Syntax:
try:
# Code that may raise an exception
# ...
except Exception as e:
# Code to handle any exception
# ...
Example:
try:
value = int(input("Enter a numerator: "))
divisor = int(input("Enter a divisor: "))
except Exception as e:
print(f"Error: {e}")
Utilizing a generic except block can be beneficial when you aim to offer a
fallback or default behavior for unexpected exceptions.
Syntax:
try:
# Code that may raise an exception
# ...
except ExceptionType as e:
# Code to handle the exception
# ...
else:
# Code to execute if no exception is raised
# ...
Example:
try:
value = int(input("Enter a number: "))
result = 10 / value
except ValueError as e:
print(f"Error: Invalid input ({e})")
except ZeroDivisionError as e:
print(f"Error: Division by zero ({e})")
else:
print(f"Result: {result}")
```
In this example:
1. The `try` block attempts to get user input and perform a division.
2. If the user enters an invalid number (raises `ValueError`) or attempts to divide
by zero (raises `ZeroDivisionError`), the corresponding `except` block is
executed.
3. If no exception is raised in the `try` block, the `else` block is executed, and it
prints the result of the division.
Key Points:
• The `else` block is optional and comes after all `except` blocks.
• The code in the `else` block is executed only if no exceptions are raised in
the `try` block.
• It helps in separating the code that may raise exceptions from the code
that should run when everything goes smoothly.
• Use `else` when you want to perform actions that should only happen
when no exceptions occur.
• It improves code readability by making it clear which part of the code is
responsible for handling exceptions and which part is executed when no
exceptions are raised.
try:
# Code that may raise an exception
# ...
except ExceptionType as e:
# Code to handle the exception
# ...
else:
# Code to execute if no exception is raised
# ...
Adding the `else` block makes the structure more intuitive and can make the
code more readable by avoiding unnecessary indentation of the success case.
7. try except else finally:
In Python, the `try`, `except`, `else`, and `finally` blocks can be combined to
create a comprehensive exception-handling structure. Each block serves a
distinct purpose:
Syntax:
try:
# Code that may raise an exception
# ...
except ExceptionType as e:
# Code to handle the exception
# ...
else:
# Code to execute if no exception is raised
# ...
finally:
# Code to execute regardless of exceptions
# ...
Example:
try:
value = int(input("Enter a number: "))
result = 10 / value
except ValueError as e:
print(f"Error: Invalid input ({e})")
except ZeroDivisionError as e:
print(f"Error: Division by zero ({e})")
else:
print(f"Result: {result}")
finally:
print("This code always executes, regardless of exceptions.")
In this example:
1. The `try` block attempts to get user input and perform a division.
2. If the user enters an invalid number (raises `ValueError`) or attempts to divide
by zero (raises `ZeroDivisionError`), the corresponding `except` block is
executed.
3. If no exception is raised in the `try` block, the `else` block is executed,
printing the result of the division.
4. The `finally` block contains code that always executes, regardless of whether
an exception occurred or not. It is commonly used for cleanup operations.
Key Points:
• The `else` block is optional and comes after all `except` blocks. It
executes only if no exceptions are raised.
• The `finally` block is optional and comes after the `else` block. It
executes regardless of whether an exception occurred or not.
• The `else` and `finally` blocks are often used together when you want to
perform specific actions regardless of whether an exception occurred.
Using `try`, `except`, `else`, and `finally` together provides a comprehensive
structure for handling exceptions, ensuring that your code can gracefully
manage errors and execute cleanup operations as needed.
8. raise:
Syntax:
try:
age = int(input("Enter your age: "))
if age < 0:
raise ValueError("Age cannot be negative")
except ValueError as e:
print(f"Error: {e}")
In this example, if the user enters a negative age, a `ValueError` is raised with a
custom error message.
7.2 Creating and Raising a Custom Exception:
class CustomError(Exception):
pass
try:
raise CustomError("This is a custom exception")
except CustomError as e:
print(f"Custom Error: {e}")
Here, a custom exception `CustomError` is defined, and then it's raised in the
`try` block with a custom message.
Key Points:
• The `raise` statement interrupts the normal flow of the program and raises
an exception.
• You can raise built-in exceptions or create your own custom exceptions
by defining a new class that inherits from the `Exception` class (or its
subclasses).
• The `raise` statement can include an optional custom message to provide
additional information about the reason for raising the exception.
Using `raise` is helpful when you want to handle exceptional cases that are not
automatically detected by the interpreter. It allows you to communicate specific
error conditions and take appropriate actions in response to those conditions.
9. assert:
Syntax:
Example:
try:
result = divide(10, 0)
except AssertionError as e:
print(f"Assertion Error: {e}")
• The `assert` statement is a debugging tool and should not be used for
handling runtime errors in production code.
• If Python is run with the `-O` (optimize) command-line switch, assertions
are ignored, and the corresponding code is not executed.
• It is advisable to use `assert` for checking conditions that should always
be true, indicating a bug in the program if they are false.