Python

P
PythonHub
Progress 0%

Python

  • Home
  • History of Python
  • Applications of Python
  • Introduction To Python
    • What is Python
    • Character Set
    • Tokens in Python
    • Python Execution Mode
    • Variable And Identifiers
    • Data Types in Python
    • Operators And Expressions
    • Constants in Python
    • Assignment Statement
    • Input / Output in Python
    • Simple Python Scripts
    • Namespace in Python
    • 📝 Assignments
  • Operators in Python
    • Arithmetic Operators
    • Assignment Operators
    • Shorthand Assignment Operators
    • Relational Operators
    • Logical Operators
    • Bitwise Operators
    • Special Operators
    • 📝 Assignments
  • Input Output in Python
    • Accept Input
    • Output Formatting
    • 📝 Assignments
  • Conditional Statement
    • Decision Making
    • if Statement
    • IF-ELSE STATEMENT
    • IF-ELSE LADDER
    • NESTED IF-ELSE
    • Short Hand IF-ELSE
    • 📝 Assignments
  • Loops
    • Introduction to Loops
    • While Loop
    • Nested While Loop
    • 📝 While Loop Assignments
    • For Loop
    • For Loop Examples
    • Nested For Loop
    • Nested For Loop Examples
    • Infinite While Loops
    • Infinite For Loops
    • Break, Continue and Else in Loops
    • Difference Between For and While Loop
    • For Each Loop
    • 📝 For Each Assignments
    • 📝 All Loops Assignments
  • List
    • List in Python
    • Access List Elements
    • List Functions
    • Iterate (Loop) List
    • List Comprehension
    • 📝 Assignments
  • Tuple
    • Tuple in Python
    • Access Tuple Elements
    • Tuple Functions
    • Iterate (Loop) Tuple
    • Unpack Tuple
    • Tuple Comprehension
    • 📝 Assignments
  • Set
    • Set in Python
    • Access Set Elements
    • Set Methods
    • Iterate (Loop) Set
    • Pack/Unpack Set
    • Set Comprehension
    • 📝 Assignments
  • Dictionary
    • Dictionary
    • Access Dictionary Items
    • Dictionary Methods
    • Iterate (Loop) Dictionary
    • Formatting Dictionaries
    • Nested Dictionaries
    • Dictionary Comprehension
    • 📝 Assignments
  • Diff List Tuple Set Dictionary
    • List vs Tuple
    • List vs Set
    • List vs Dictionary
    • Tuple vs Set
    • Tuple vs Dictionary
    • Dictionary vs Set
    • 📝 Assignments
  • Exception
    • Error vs Exception
    • Types of Exception
    • Exception Handling
    • User Defined Exception
    • Logging Exception
    • 📝 Assignments
  • Functions
    • Introduction to Functions
    • Modular Programming
    • Types of Functions
    • Inbuilt Functions
    • Need For User-Defined Function
    • Elements of User Defined Function
    • Function Arguments
    • Nesting of Functions
    • Recursion
    • Global Local and Non Local
    • Python Lambda Functions
    • 📝 Assignments
  • Python Module
    • Introduction to Module
    • Inbuilt Modules in Python
    • User Defined Module
    • 📝 Assignments
  • File Handling
    • Introduction to Files
    • Create File
    • Read Files
    • Write to File
    • Rename File
    • Copy File
    • Move File
    • List Files in Directory
    • Binary Files
    • Zipping and Unzipping Files
    • 📝 Assignments
  • Strings
    • Basics of Strings
    • String Special Operators
    • String Formatting Operators
    • String Methods
    • 📝 Assignments
  • Regular Expressions
  • Python OOPS
    • Basics of Object Oriented
    • What are Classes and Objects?
    • Creating Class and Object
    • OOP vs Procedural Programming
    • Difference Between Classes and Objects
    • Constructors
    • Destructor
    • Built Class Methods and Attributes
    • Class and Instance Variables
    • Inheritance in Python
    • Single Inheritance
    • Multiple Inheritance
    • Multilevel Inheritance
    • Hierarchical Inheritance
    • Hybrid Inheritance
    • Abstraction
    • Method Overriding
    • Abstract Method
    • Interfaces in Python
    • Abstract Class vs Interface
    • Public, Private and Protected
    • Overloading vs Overriding
    • Inheritance vs Composition
    • Encapsulation
    • Polymorphism
    • Inner Classes
    • 📝 Assignments
  • Advanced Python
    • Iterator in Python
    • Generator in Python
    • Decorator in Python
    • Type Hints in Python
    • Async/Await Programming
    • Dataclasses in Python
    • Context Managers in Python
    • Property Decorator in Python
    • __slots__ in Python
    • Enums in Python
    • Walrus Operator in Python
    • Match-Case in Python
    • 📝 Assignments
  • Python Standard Library
    • Collections Module
    • Itertools Module
    • Functools Module
    • Datetime Module
    • JSON Module
    • OS Module
    • Sys Module
    • Random Module
    • Math Module
    • 📝 Assignments
  • Python Testing
    • Unit Testing in Python
    • Pytest Framework
    • Mocking in Python
    • 📝 Assignments
  • Python Best Practices
    • PEP 8 Style Guide
    • Docstrings in Python
    • Logging in Python
    • Code Optimization Tips
    • Debugging Techniques
    • 📝 Assignments
  • MySQL Database in Python
    • Introduction to MySQL with Python
    • DBMS vs File System
    • Connecting to MySQL Database
    • Create Database in MySQL
    • Create Table in MySQL
    • Insert Data in MySQL
    • Insert Multiple Rows
    • Select Data from MySQL
    • WHERE Clause in MySQL
    • Update Data in MySQL
    • Delete Data from MySQL
    • Parameterized Queries
    • Transaction Management
    • Error Handling
    • Connection Pooling
    • MySQL Drivers Guide
    • Joins in MySQL
    • Aggregation Functions
    • Backup MySQL Database
    • Best Practices
    • 📝 Assignments
  • MySQL Database Operations
    • SELECT Statement
    • MySQL Operators
    • DDL Statements
    • DML Statements
    • Subqueries
    • JOIN Operations
    • Aggregation
    • Case Study
    • 📝 Assignments
  • Graphics in Python
  • Threads in Python
    • Introduction to Threads
    • Process vs Threads
    • Concurrent Programming & GIL
    • Uses of Threads
    • Creating Threads
    • Single Tasking
    • Multi Tasking
    • Thread Synchronization
    • 📝 Assignments
  • Interview Questions & Answers
  • Python Case Studies
  • Multiple Choice Questions
  • 📝 Practice Problems
Get in Touch
  • tech2dsm@gmail.com

© Sankalan Data Tech

Python Language Interactive Tutorial

Python: User Defined Exceptions

Python User Defined Exception - Complete Guide

Learn how to create and use custom exceptions in Python by inheriting from the Exception class.

Created by Sankalan Data Tech Team Verified
Data Engineers, Analysts, Scientists & Trainers
Created by experienced Python developers, data engineers, and data scientists to make programming easy through practical examples, real-world experience, and clear explanations.
On this page:
  • What are User Defined Exceptions?
  • Why Create Custom Exceptions?
  • Creating a Custom Exception
  • Adding Custom Attributes
  • Raising Custom Exceptions
  • Handling Custom Exceptions
  • Inheritance and Exception Hierarchy
  • Best Practices
  • Common Mistakes
  • Try It Yourself
  • Quiz
  • FAQ
Share this tutorial:
Twitter LinkedIn Facebook WhatsApp Reddit Telegram Email Copy Link
What You'll Learn Here
  • What are user defined exceptions — definition and purpose
  • Why create custom exceptions — benefits and use cases
  • Creating custom exceptions — inheriting from Exception class
  • Adding custom attributes — storing additional data
  • Raising custom exceptions — using the raise keyword
  • Handling custom exceptions — try-except with custom exceptions
  • Exception hierarchy — organizing custom exceptions
  • Best practices — writing clean custom exceptions

What are User Defined Exceptions?

User defined exceptions are custom exception classes that you create by inheriting from Python's built-in Exception class. They allow you to define application-specific error types that are meaningful to your program's domain.

Definition: A user defined exception is a class that inherits from the Exception class (or any of its subclasses) and is used to represent errors that are specific to your application's logic or domain.

💡 Key concept: User defined exceptions make your code more readable and maintainable by using meaningful error names instead of generic built-in exceptions.

Why Create Custom Exceptions?

1

Benefits of Custom Exceptions

Creating custom exceptions provides several important benefits:

# 1. Meaningful error names
class InsufficientFundsError(Exception):
    """Raised when a bank account has insufficient funds"""
    pass

# 2. Better error messages with context
class InvalidAgeError(Exception):
    def __init__(self, age, message="Age must be between 0 and 150"):
        self.age = age
        self.message = message
        super().__init__(f"Invalid age {age}: {message}")

# 3. Organized error hierarchy
class AppError(Exception):
    pass

class DatabaseError(AppError):
    pass

class ValidationError(AppError):
    pass

# 4. Specific error handling
try:
    withdraw_money(1000)
except InsufficientFundsError as e:
    # Handle insufficient funds specifically
    print(f"Please add funds to your account. {e}")
except Exception as e:
    # Handle other errors
    print(f"Unexpected error: {e}")

Benefits:

  • Readability — meaningful error names make code self-documenting
  • Specificity — catch and handle specific error types
  • Context — carry additional error information
  • Organization — group related errors in a hierarchy
  • Debugging — easier to identify and fix issues

Quick Check: What is the main benefit of using custom exceptions? (Answer: They make code more readable and allow specific error handling)

Creating a Custom Exception

2

Basic Custom Exception

Creating a custom exception is as simple as creating a class that inherits from Exception. The convention is to use the suffix "Error" in the class name.

# Basic custom exception (minimal)
class CustomError(Exception):
    """Custom exception for application-specific errors"""
    pass

# Using the custom exception
try:
    raise CustomError("Something went wrong!")
except CustomError as e:
    print(f"Caught custom error: {e}")

# Another example
class NegativeNumberError(Exception):
    """Raised when a negative number is not allowed"""
    pass

def check_positive(number):
    if number < 0:
        raise NegativeNumberError(f"Number must be positive, got {number}")
    return True

try:
    check_positive(-5)
except NegativeNumberError as e:
    print(f"Validation failed: {e}")

Key points:

  • Inherit from Exception class (or its subclasses)
  • Add a docstring for documentation
  • Use pass for minimal implementation
  • Convention: name ends with Error
  • Can be raised and caught like built-in exceptions

Quick Check: What class should a custom exception inherit from? (Answer: Exception)

Adding Custom Attributes

3

Creating Informative Exceptions

You can add custom attributes and methods to your exception classes to carry additional information about the error.

# Custom exception with attributes
class InsufficientFundsError(Exception):
    """Raised when an account doesn't have enough funds"""
    
    def __init__(self, balance, amount, account_id=None):
        self.balance = balance
        self.amount = amount
        self.account_id = account_id
        self.shortfall = amount - balance
        
        message = f"Insufficient funds: balance {balance}, needed {amount}"
        if account_id:
            message += f" (Account: {account_id})"
        super().__init__(message)

# Using the exception
try:
    balance = 100
    amount = 150
    raise InsufficientFundsError(balance, amount, account_id="ACC-001")
except InsufficientFundsError as e:
    print(f"Error: {e}")
    print(f"Balance: {e.balance}")
    print(f"Needed: {e.amount}")
    print(f"Shortfall: {e.shortfall}")
    print(f"Account: {e.account_id}")

# Output:
# Error: Insufficient funds: balance 100, needed 150 (Account: ACC-001)
# Balance: 100
# Needed: 150
# Shortfall: 50
# Account: ACC-001

Key points:

  • Define __init__ method to accept custom data
  • Store data as attributes for later access
  • Call super().__init__(message) to set the error message
  • Attributes make debugging easier

Quick Check: How do you add custom data to an exception? (Answer: By defining __init__ and storing attributes)

Raising Custom Exceptions

4

Triggering Custom Exceptions

You raise custom exceptions the same way as built-in exceptions — using the raise keyword.

# Raising custom exceptions
class ValidationError(Exception):
    pass

class AgeValidationError(ValidationError):
    def __init__(self, age, message="Invalid age"):
        self.age = age
        super().__init__(f"{message}: {age}")

def validate_user_age(age):
    if age < 0:
        raise AgeValidationError(age, "Age cannot be negative")
    if age > 150:
        raise AgeValidationError(age, "Age cannot exceed 150")
    return True

# Using validation
try:
    validate_user_age(-5)
except AgeValidationError as e:
    print(f"Age validation failed: {e}")
    print(f"Invalid age: {e.age}")

# Raising in a function
class ConfigError(Exception):
    pass

def load_config(filename):
    if not filename:
        raise ConfigError("Config filename cannot be empty")
    # ... rest of function

Key points:

  • Use raise keyword to trigger custom exceptions
  • Pass arguments to the exception constructor
  • Custom exceptions can be raised in any context
  • They behave exactly like built-in exceptions

Quick Check: How do you raise a custom exception? (Answer: Using the raise keyword)

Handling Custom Exceptions

5

Catching Custom Exceptions

Custom exceptions are caught using try-except blocks, just like built-in exceptions.

# Defining custom exceptions
class DatabaseError(Exception):
    pass

class ConnectionError(DatabaseError):
    def __init__(self, host, port):
        self.host = host
        self.port = port
        super().__init__(f"Failed to connect to {host}:{port}")

class QueryError(DatabaseError):
    def __init__(self, query, error):
        self.query = query
        self.original_error = error
        super().__init__(f"Query failed: {query} - {error}")

# Handling custom exceptions
def execute_query(query, host="localhost", port=5432):
    try:
        # Simulate database connection
        if host == "unknown":
            raise ConnectionError(host, port)
        if "DROP TABLE" in query.upper():
            raise QueryError(query, "DROP TABLE not allowed")
        return "Query executed successfully"
    except ConnectionError as e:
        print(f"Connection failed to {e.host}:{e.port}")
        return None
    except QueryError as e:
        print(f"Query failed: {e.query}")
        return None
    except DatabaseError as e:
        print(f"Database error: {e}")
        return None

# Testing
print(execute_query("SELECT * FROM users"))
print(execute_query("DROP TABLE users"))
print(execute_query("SELECT * FROM users", host="unknown"))

Key points:

  • Custom exceptions are caught like built-in exceptions
  • You can catch specific custom exceptions
  • You can catch parent exceptions to handle groups
  • Order matters — catch more specific exceptions first

Quick Check: Can you catch custom exceptions with try-except? (Answer: Yes, just like built-in exceptions)

Inheritance and Exception Hierarchy

6

Organizing Custom Exceptions

You can create a hierarchy of custom exceptions by having them inherit from each other. This allows you to catch groups of related exceptions.

# Creating an exception hierarchy
class AppError(Exception):
    """Base exception for all application errors"""
    pass

class ValidationError(AppError):
    """Raised when validation fails"""
    pass

class InputValidationError(ValidationError):
    """Raised when user input validation fails"""
    pass

class DataValidationError(ValidationError):
    """Raised when data validation fails"""
    pass

class DatabaseError(AppError):
    """Raised when database operations fail"""
    pass

class ConnectionError(DatabaseError):
    """Raised when database connection fails"""
    pass

class QueryError(DatabaseError):
    """Raised when a database query fails"""
    pass

# Using the hierarchy
def process_data(data):
    try:
        # Some validation
        if not isinstance(data, dict):
            raise InputValidationError("Data must be a dictionary")
        if "name" not in data:
            raise DataValidationError("Missing 'name' field")
        
        # Try database operation
        try:
            save_to_db(data)
        except ConnectionError:
            print("Database connection failed")
            return
        except QueryError:
            print("Query failed")
            return
            
    except ValidationError as e:
        # Catches both InputValidationError and DataValidationError
        print(f"Validation error: {e}")
    except DatabaseError as e:
        # Catches both ConnectionError and QueryError
        print(f"Database error: {e}")
    except AppError as e:
        # Catches all application errors
        print(f"Application error: {e}")
    except Exception as e:
        # Catches everything else
        print(f"Unexpected error: {e}")

Key points:

  • Create a base exception for your application
  • Group related exceptions in a hierarchy
  • Catching a parent exception catches all child exceptions
  • Makes error handling more organized

Quick Check: What happens when you catch a parent exception? (Answer: All child exceptions are also caught)

Best Practices

7

Writing Clean Custom Exceptions

# 1. Use meaningful names
# GOOD
class UserNotFoundError(Exception):
    pass

# AVOID
class Error(Exception):
    pass

# 2. Add docstrings
class ConfigurationError(Exception):
    """Raised when configuration is invalid or missing"""
    pass

# 3. Include relevant context
class FileProcessingError(Exception):
    def __init__(self, filename, operation, error):
        self.filename = filename
        self.operation = operation
        self.error = error
        super().__init__(f"Failed to {operation} {filename}: {error}")

# 4. Create a base exception for your application
class AppError(Exception):
    """Base exception for MyApp"""
    pass

# 5. Use inheritance for organization
class ConfigError(AppError):
    pass

class DataError(AppError):
    pass

# 6. Don't overuse custom exceptions
# Only create them when they add value
class UserAlreadyExistsError(Exception):
    """Raised when trying to create a user that already exists"""
    pass

Best practices summary:

  • Use meaningful names — end with "Error"
  • Add docstrings — document what the exception means
  • Include context — add attributes for debugging
  • Create a base exception — for your application
  • Don't overuse — only create when they add value

Common Mistakes

8

Things to Watch Out For

Inheriting from the Wrong Class

# WRONG — inheriting from object
class MyError(object):  # Not an exception!
    pass

# CORRECT — inheriting from Exception
class MyError(Exception):
    pass

Not Adding a Docstring

# AVOID — no documentation
class ConfigError(Exception):
    pass

# GOOD — with docstring
class ConfigError(Exception):
    """Raised when configuration is invalid or missing"""
    pass

Using Vague or Generic Names

# AVOID — too generic
class Error(Exception):
    pass

# GOOD — specific and descriptive
class InvalidCredentialsError(Exception):
    pass

class SessionExpiredError(Exception):
    pass

Quick Check: What is the most common mistake with custom exceptions? (Answer: Inheriting from the wrong class or using vague names)

Try It Yourself

Experiment with user defined exceptions in the editor below. Modify the code and see what happens.

Loading Pyodide... 0%
Python Code Editor
========================================
USER DEFINED EXCEPTION PRACTICE
========================================

1. BASIC CUSTOM EXCEPTION
Caught: Number must be positive, got -5

2. CUSTOM EXCEPTION WITH ATTRIBUTES
Error: Insufficient funds: balance 100, needed 150
Balance: 100, Needed: 150

3. EXCEPTION HIERARCHY
AgeError caught: Age cannot be negative: -5

User defined exception practice complete!
🏆

You've Got It!

You now understand user defined exceptions — how to create them, add custom attributes, raise them, handle them, and organize them in a hierarchy. This is a professional skill for writing robust Python applications!

Quick Quiz

Test what you've learned:

1. What class should a custom exception inherit from?
2. What is the convention for naming custom exceptions?
3. How do you add custom data to an exception?
4. What keyword is used to raise a custom exception?
5. What happens when you catch a parent exception?

Frequently Asked Questions

What is a user defined exception? ▼

A user defined exception is a custom exception class created by inheriting from Python's built-in Exception class. It represents application-specific errors.

Why should I create custom exceptions? ▼

Custom exceptions make your code more readable, allow specific error handling, carry additional context, and help organize error types in a hierarchy.

What class should a custom exception inherit from? ▼

Custom exceptions should inherit from the Exception class (or a subclass of Exception). This makes them behave like built-in exceptions.

Can I add custom data to a custom exception? ▼

Yes, by defining the __init__ method and storing data as attributes. This is useful for debugging and error reporting.

What is the exception hierarchy? ▼

The exception hierarchy is a way to organize custom exceptions by having them inherit from each other. This allows catching groups of related exceptions.

What's a common interview question about custom exceptions? ▼

Common questions include: "How do you create a custom exception in Python?" and "What is the difference between a built-in and user-defined exception?"

Where to Go From Here

Now that you understand user defined exceptions, check out these related topics:

Logging Exception

Learn how to log exceptions for debugging and monitoring.

Learn More →

Exception Assignments

Practice what you've learned with assignments.

Learn More →

Error vs Exception

Review the difference between errors and exceptions.

Learn More →
Interview Resources
  • Python Syntax & Variables Interview Questions
  • Top SQL Interview Questions & Answers
  • SQL Joins: Displaying Data from Multiple Tables FAQ
Previous: Exception Handling Next: Logging Exception →