In programming, exceptions are unexpected events or errors that can disrupt the normal flow of a program. Python provides a mechanism to handle these exceptions, preventing the program from crashing and enabling the developer to respond to errors in a controlled manner.
In this guide, we’ll explore:
try
, except
, else
, and finally
An exception is an error that occurs during the execution of a program, causing the normal flow of the program to be interrupted. When an exception is raised, Python stops executing the code in the current block and looks for a way to handle the error. If the exception is not handled, the program will terminate and display an error message.
# Division by zero (will raise an exception)
result = 10 / 0
In this case, dividing by zero will raise a ZeroDivisionError
, and Python will terminate the program unless the exception is caught and handled.
Python provides a rich set of built-in exceptions, each designed for a specific type of error. Some of the common built-in exceptions include:
ZeroDivisionError
: Raised when a number is divided by zero.ValueError
: Raised when a function receives an argument of the right type but an inappropriate value.TypeError
: Raised when an operation or function is applied to an object of inappropriate type.FileNotFoundError
: Raised when trying to open a file that does not exist.IndexError
: Raised when an index is out of range for a list or tuple.KeyError
: Raised when trying to access a dictionary with a key that does not exist.AttributeError
: Raised when an invalid attribute reference is made on an object.Each of these exceptions helps developers identify and handle specific types of errors in their code.
try
, except
, else
, and finally
Python provides the try
and except
blocks for handling exceptions. The general structure looks like this:
try:
# Code that might cause an exception
risky_code()
except SomeException as e:
# Code to handle the exception
handle_error(e)
try
and except
try:
# Trying to open a file that does not exist
with open('non_existent_file.txt', 'r') as file:
content = file.read()
except FileNotFoundError:
print("The file was not found.")
try
block is executed.except
block that matches the exception type (in this case, FileNotFoundError
).except
block is skipped.except
BlocksYou can handle multiple types of exceptions with separate except
blocks:
try:
num = int(input("Enter a number: "))
result = 10 / num
except ZeroDivisionError:
print("Error: Cannot divide by zero.")
except ValueError:
print("Error: Invalid input. Please enter a valid number.")
In this case:
ZeroDivisionError
will be raised and handled.ValueError
will be raised and handled.else
ClauseThe else
block runs if no exception was raised in the try
block. It’s useful for code that should only execute when no errors occur.
try:
num = int(input("Enter a number: "))
result = 10 / num
except ZeroDivisionError:
print("Error: Cannot divide by zero.")
except ValueError:
print("Error: Invalid input.")
else:
print(f"The result is {result}")
In this example:
else
block will print the result.finally
ClauseThe finally
block is executed no matter what, whether an exception occurred or not. It's typically used to clean up resources (like closing files or releasing locks).
try:
file = open('example.txt', 'r')
# Perform operations on the file
except FileNotFoundError:
print("File not found.")
finally:
file.close() # This will always execute
print("File closed.")
In this case:
Sometimes, you may want to raise your own exceptions in your program. You can use the raise
keyword to manually raise an exception.
def divide(x, y):
if y == 0:
raise ValueError("Cannot divide by zero.")
return x / y
try:
result = divide(10, 0)
except ValueError as e:
print(e)
In this example:
ValueError
when trying to divide by zero.try
block catches this error and prints the error message.You can also raise built-in exceptions or custom exceptions with the raise
keyword.
You can define your own exception classes by subclassing the built-in Exception
class. This is useful when you want to define specific error types for your application.
class CustomError(Exception):
"""Custom exception class"""
def __init__(self, message):
self.message = message
super().__init__(self.message)
def do_something(risky):
if risky:
raise CustomError("Something went wrong in the operation!")
try:
do_something(True)
except CustomError as e:
print(f"Caught an error: {e}")
In this example:
CustomError
that takes a message as input.do_something()
function.try
block.Catch Specific Exceptions: Always catch specific exceptions rather than a generic except
clause. This makes your error handling more precise and informative.
try:
result = 10 / num
except ZeroDivisionError:
print("Error: Cannot divide by zero.")
else
for Code That Should Run Only When No Exceptions Occur: The else
block ensures that your code executes only when no errors are raised, which is useful for operations that depend on successful execution of the try
block.Use finally
for Cleanup: Always use the finally
block when you need to release resources, like closing files or database connections, to ensure cleanup even when exceptions occur.
Don’t Overuse Exceptions: Exceptions should be used for exceptional cases, not for regular control flow. Avoid using exceptions for normal conditions that can be handled through regular code logic.
Create Custom Exceptions When Necessary: If your program needs to handle specific error cases, define custom exceptions to make your error handling clearer and more meaningful.