Python - Exception Handling
The with
statement in Python is used to simplify the management of resources, such as file handling, by ensuring that certain operations are performed before and after the block of code inside the with
statement. This is especially useful for exception handling because it guarantees that cleanup actions will be taken even if an exception is raised.
try:
# Open a file using with statement
with open("example.txt", "r") as file:
content = file.read()
print(content)
except FileNotFoundError as e:
print(f"Error: {e}. The specified file was not found.")
except PermissionError as e:
print(f"Error: {e}. Permission denied to access the file.")
except IOError as e:
print(f"Error: {e}. An I/O error occurred while reading the file.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
else:
print("File read successfully.")
finally:
print("File handling completed.")
In this example, the with
statement is used to open the file "example.txt" for reading. The file is automatically closed when the block inside the with
statement is exited, even if an exception occurs. This ensures proper resource cleanup without the need for an explicit file.close()
statement.
The output will be:
Error: [Errno 2] No such file or directory: 'example.txt'. The specified file was not found. File handling completed.
In Python, you can re-raise an exception using the raise
statement without providing any additional arguments. This allows you to capture an exception, perform some actions, and then raise the same exception to propagate it further. This can be useful in scenarios where you want to log information or perform custom handling before letting the exception continue its normal flow.
def example_function():
try:
# Some code that may raise an exception
x = 1 / 0
except ZeroDivisionError as e:
# Handle the exception
print(f"Caught an exception: {e}")
# Perform some actions
# Re-raise the exception
raise
try:
example_function()
except ZeroDivisionError as e:
print(f"Exception propagated: {e}")
In this example, the example_function
attempts to perform a division by zero, which raises a ZeroDivisionError
. The exception is caught within the function, some actions are performed, and then the same exception is re-raised using the raise
statement. Finally, the exception is caught again in the outer scope.
The output will be:
Caught an exception: division by zero Exception propagated: division by zero
sys.exc_info()
function in exception handling?
The sys.exc_info()
function in Python is used to get information about the most recent exception that occurred. It returns a tuple containing information about the current exception, including the exception type, the exception instance, and the traceback.
import sys
def example_function():
try:
# Some code that may raise an exception
x = 1 / 0
except ZeroDivisionError as e:
# Get information about the exception
exc_type, exc_value, exc_traceback = sys.exc_info()
# Print exception details
print(f"Exception Type: {exc_type}")
print(f"Exception Value: {exc_value}")
print(f"Exception Traceback: {exc_traceback}")
try:
example_function()
except ZeroDivisionError as e:
print(f"Caught an exception: {e}")
In this example, the example_function
attempts to perform a division by zero, which raises a ZeroDivisionError
. Inside the except
block, sys.exc_info()
is used to retrieve information about the exception. The exception type, value, and traceback are then printed.
The output will be:
Exception Type: <class 'ZeroDivisionError'> Exception Value: division by zero Exception Traceback: <traceback object at 0x...> Caught an exception: division by zero
try-except-else-finally
hierarchy.
The try-except-else-finally
hierarchy in Python is used for exception handling. It provides a structured way to handle exceptions and execute cleanup code regardless of whether an exception occurs or not.
Here's an example program that demonstrates the use of the try-except-else-finally
hierarchy:
def example_function(divisor):
try:
result = 10 / divisor
except ZeroDivisionError:
print("Cannot divide by zero!")
else:
print("Division successful. Result:", result)
finally:
print("This will always be executed, regardless of exceptions.")
# Example usage
example_function(2)
example_function(0)
In this example, the example_function
attempts to perform a division, and the try
block contains the code that might raise an exception. The except
block handles the specific exception (ZeroDivisionError
) that may occur. The else
block contains code that should run if no exception occurs. The finally
block contains code that will always run, regardless of whether an exception occurred or not.
The output will be:
Division successful. Result: 5.0 Cannot divide by zero! This will always be executed, regardless of exceptions. This will always be executed, regardless of exceptions.