A Comprehensive Guide to Exception Handling in Python

A Comprehensive Guide to Exception Handling in Python

Introduction

Exceptions occur when unexpected events disrupt the normal flow of program execution. Python has built-in exception handling constructs that allow gracefully handling errors and restoring normal flow. Proper exception handling is critical for developing robust programs in Python.

In this article, we will dive into Python exception concepts and exception handling in Python techniques with simple code examples.

What are Exceptions?

Exceptions, or runtime errors, are triggered when issues like missing files, network outages, invalid user input, division by zero etc. occur while a program is running.

For example, trying to open a non-existent file causes a FileNotFoundError exception:

file = open('missing.txt') # Trigger FileNotFoundError

Exceptions immediately halt program execution and print a stack trace if not handled. Proper exception handling prevents abrupt crashes.

Exception Handling in python Using try…except

Catching Exceptions

We can catch and handle exceptions using try and except blocks:

try:
   file = open('test.txt')	
   data = file.read()
   file.close()
except FileNotFoundError:
   print('File not found')

This gracefully handles the missing file instead of a crashing traceback.

We can specify different handling based on exception type:

try:
   file = open('test.txt')	
   file.write('Hello') # Will cause Exception
   x = 10/0		 # Will cause ZeroDivisionError
except FileNotFoundError:
   print('File not found')
except ZeroDivisionError:
   print('Division by zero!')

The except block that matches the exception type is executed. We can have multiple except blocks to handle different failures differently.

Catching All Exceptions

We can use the root Exception class to generically catch all exceptions:

try:
   # Code that may have exceptions
except Exception as e:
   print('An error occurred:', e)
   raise # Optionally re-raise same exception

This prints the exception message without halting the program. The raise keyword can be used to re-raise the same exception after handling.

Finally Block

The finally block allows executing cleanup code that should always run, with or without exceptions:

try:
   file = open('test.txt')
   # Process file  
except FileNotFoundError as e:
   print('File not found') 
finally:
   print('Executing finally block')

The finally block runs after normal execution or exception handling to release resources. This ensures critical cleanup like closing files always occurs.

Raising Exceptions in python

We can manually raise exceptions using the raise keyword:

def check_age(age):
  if age < 0:
    raise ValueError('Age cannot be negative')
		
  if age % 2 == 0:
    print('Age is even')

check_age(-10) # Raises ValueError

Raising meaningful exceptions helps signal invalid program state.

Custom Exceptions in Python

Python also allows defining custom exception classes inheriting from Exception:

class InvalidNameException(Exception):
  pass

name = '123' # Invalid name 

if not name.isalpha():
  raise InvalidNameException

This enables raising exceptions in python specific to our application for clearer error handling.

Built-in Exceptions in Python

Python has many built-in exceptions that are raised automatically:

ExceptionCause
ZeroDivisionErrorDivision by zero
OverflowErrorMath operation exceeds max limit
FileNotFoundErrorFile or directory not found
ConnectionErrorNetwork issue like DNS failure, refused connection
ValueErrorInvalid argument passed
KeyErrorMissing key for a dict or object
AttributeErrorAttribute reference fails
ImportErrorImport module fails
KeyboardInterruptUser interrupts program execution
Common built-in exceptions

These common exceptions cover a wide variety of error scenarios.

Conclusion

Robust error handling with exceptions is critical for building reliable Python programs. The language provides simple yet powerful constructs like try-except-finally blocks and the raise keyword to implement exception handling. This allows detecting and recovering gracefully from unexpected events and invalid states instead of abrupt crashes. Mastering Python’s exception support results in fault-tolerant applications.

Frequently Asked Questions

  1. What happens when an exception is not caught in Python?

Uncaught exceptions in Python generate tracebacks and halt program execution. The stack trace helps debug the error.

  1. How do you catch multiple exceptions in Python?

Use multiple except blocks with the specific Exception classes to handle different errors differently.

  1. When should you use finally versus except blocks?

finally always runs after try/except to release resources. except runs only on matching exceptions.

  1. What is the purpose of raising exceptions in Python?

Raising exceptions helps signal abnormal conditions and invalid program states so they can be handled gracefully.

  1. How do you create a custom exception class in Python?

Custom exceptions can be defined by subclassing the built-in Exception class with custom logic.

  1. What are some common built-in exceptions in Python?

ZeroDivisionError, ValueError, FileNotFoundError, TypeError, ImportError etc. are some common built-in exceptions.

  1. What happens when you re-raise an exception in Python?

Using the raise statement without arguments re-raises the current exception being handled allowing outer handlers to catch it.

  1. Should all exceptions be caught and handled in Python?

It’s recommended to catch and handle exceptions that can be programatically recovered from. Some like KeyboardInterrupt may not need handling.

  1. What is the best way to print the exception message in Python?

Printing the exception object passed to the except block prints its message nicely – print(e).

  1. How do you handle multiple exceptions with the same handling logic?

Related exceptions can be grouped in a parent except block to reuse the same handling logic and simplify code.

Leave a Reply

Your email address will not be published. Required fields are marked *