Exception handling is a crucial aspect of writing robust and reliable Python code. Whether you’re a beginner or an experienced developer, getting an error, or exception, in your Python program means the entire program will crash. You don’t want this to happen in real-world programs. Instead, you want the program to detect errors, handle them, and then continue to run. In this blog, we’ll explore the fundamentals of exception handling in Python, including syntax, best practices, and advanced techniques.


What Are Exceptions?

Exceptions are runtime errors that disrupt the normal flow of a program. For example, trying to open a non-existent file, dividing by zero, or accessing an invalid index in a list will raise exceptions. If unhandled, these exceptions cause your program to crash.


Basic Syntax: try and except

The primary mechanism for handling exceptions in Python is the try-except block. Errors can be handled with with this. The code that could potentially have an error is put in a try clause. The program execution moves to the start of a following except clause if an error happens.

Here’s the basic structure:

def cal(value):
    try:
        return 10 / value
    except ZeroDivisionError:
        print("Cannot divide by zero!")
print(cal(0))
print(cal(2))
print(cal(3))

How It Works:

  1. The code inside the try block is executed.
  2. If an exception occurs, Python checks the except blocks for a matching exception type.
  3. If a match is found, the corresponding except block runs.

Catching Specific Exceptions

Always catch specific exceptions to avoid silencing unexpected errors. Python has many built-in exceptions (e.g., ValueError, TypeError, FileNotFoundError).

import math

x = int(input('Please enter a positive number: '))

try:
    print(f'Square Root of {x} is {math.sqrt(x)}')
except ValueError:
    print('Number is less than 0')

Output

The else Clause

The else block runs only if no exceptions were raised in the try block. Use it to separate “happy path” code from error handling.

import math
def sqr(value):

    try:
        x = math.sqrt(value)
    except ValueError:
        print('Number is less than 0')
    else:
        print(f'The Answer is: {x}')


value = int(input('Please enter a positive number: '))
sqr(value)

Output

The finally Clause

The finally block runs regardless of whether an exception occurred. It’s ideal for cleanup tasks (e.g., closing files or releasing resources).

import math

def sqr(value):

    try:
        x = math.sqrt(value)
    except ValueError:
        print('Error')
    else:
        print(f'The Answer is: {x}')
    finally:
        print('Program Ends')


value = int(input('Please enter a positive number: '))
sqr(value)

Output

Raising Exceptions Manually

Use the raise keyword to trigger exceptions intentionally. This is useful for enforcing constraints.

def validate_age(age):
    if age < 0:
        raise ValueError("Age cannot be negative!")
    return age

try:
    validate_age(-5)
except ValueError as e:
    print(e)  

Creating Custom Exceptions

Define custom exceptions by subclassing Python’s built-in Exception class. This makes your code more readable and errors more descriptive. (note: I have used RegEx, for that blog will be out soon :) )

import re
class InvalidEmailError(Exception):
    """Raised when an email format is invalid."""
    pass


def send_email(valid,email):
    if not valid:
        raise InvalidEmailError(f"Invalid email: {email}")

email = input('Please enter your email: ')
valid = re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email)
try:
    send_email(valid, email)
except InvalidEmailError as e:
    print(e)

Output


Logging a Python Error

We can Log an exception in Python with an error. This can be done in the logging.exception() method. This function logs a message with level ERROR on this logger.

import math
import logging
def sqr(value):

    try:
        x = math.sqrt(value)
    except ValueError:
        logging.exception("Error")
    else:
        print(f'The Answer is: {x}')
    finally: 
        print('Program Ends')


value = int(input('Please enter a positive number: '))
sqr(value)

Output


Best Practices for Exception Handling

  • Catch specific exceptions: Avoid broad except: clauses that hide bugs.
  • Keep try blocks minimal: Only wrap code that might raise an exception.
  • Use finally for cleanup: Ensure resources are released (e.g., closing files).
  • Log exceptions: Use logging.error() instead of print() for production code.
  • Provide meaningful messages: Help debug issues faster with clear error descriptions.
  • Avoid empty except blocks: Silent failures make debugging harder.

Conclusion

Exception handling is essential for writing better Python applications. By using try-except blocks effectively, catching specific errors, and with else/finally clauses, you can create programs that handle unexpected scenarios.

Now go forth and write bulletproof Python code!