Of course! Let's dive deep into Python's exception handling mechanism. The term myexception isn't a built-in Python keyword, but it's a perfect way to learn how to create and use your own custom exceptions.

This guide will cover everything from the basics of handling built-in exceptions to creating your own powerful, descriptive custom exceptions.
Part 1: The Basics of Exception Handling
Before we create our own, let's understand how to handle the ones Python already provides. This is done with the try...except...raise block.
Why Use Exceptions?
Imagine you're writing a program that asks a user for their age and then divides 100 by that age.
# A problematic piece of code
age_str = input("Please enter your age: ")
age = int(age_str)
result = 100 / age
print(f"You have 100/{age} = {result} years of experience!")
What happens if the user enters:

"twenty"?int("twenty")will fail with aValueError."0"?100 / 0will fail with aZeroDivisionError.
These errors would crash your program. Exception handling allows you to "catch" these errors and handle them gracefully instead of crashing.
The try...except Block
The try...except block is the core of exception handling.
try:
# Code that might cause an error
age_str = input("Please enter your age: ")
age = int(age_str)
result = 100 / age
print(f"You have 100/{age} = {result} years of experience!")
except ValueError:
# This block runs ONLY if a ValueError occurs in the 'try' block
print("Invalid input. Please enter a whole number.")
except ZeroDivisionError:
# This block runs ONLY if a ZeroDivisionError occurs
print("You can't be zero years old! Please enter a positive number.")
except Exception as e:
# A catch-all for any other unexpected errors
print(f"An unexpected error occurred: {e}")
print("Program finished successfully.")
How it works:
- Python tries to execute the code inside the
tryblock. - If an error (an "exception") occurs, it immediately jumps to the
exceptblock that matches that error type. - If no error occurs, the
exceptblocks are skipped entirely. - The program continues running after the
try...exceptblock.
Part 2: Creating Your Own Custom Exception (myexception)
Now for the main event! Creating your own exceptions makes your code more readable, maintainable, and professional. You create custom exceptions by subclassing Python's built-in Exception class.

Why Create a Custom Exception?
- Clarity: Instead of a generic
ValueError, you can raise aNegativeAgeError, which is much more specific and easier to understand. - Control: You can handle different types of errors in different ways. Your code can catch
NegativeAgeErrorand show a specific message, while aValueErrormight be handled differently. - API Design: If you're writing a library or a large application, custom exceptions allow you to define a clear "contract" for the errors your functions can raise.
Step 1: Define Your Custom Exception Class
The convention is to name your exception classes ending with Error.
# myexceptions.py
# It's good practice to inherit from Python's base Exception class
class MyCustomError(Exception):
"""Base class for other custom exceptions."""
pass
class NegativeAgeError(MyCustomError):
"""Raised when an age value is negative."""
def __init__(self, age, message="Age cannot be negative"):
self.age = age
self.message = message
super().__init__(self.message)
class InvalidAgeTypeError(MyCustomError):
"""Raised when the age is not an integer."""
def __init__(self, age_type, message="Age must be an integer"):
self.age_type = age_type
self.message = message
super().__init__(self.message)
Explanation:
- We define
NegativeAgeErrorandInvalidAgeTypeErrorthat both inherit fromMyCustomError. - By inheriting from
Exception, our new classes become exceptions themselves. - We can add custom attributes (like
self.age) and a custommessageto make our errors more informative. super().__init__(self.message)calls the constructor of the parent class (Exception) and passes the message to it. This is crucial for the error to be displayed correctly.
Step 2: Raise Your Custom Exception
Now, let's modify our age-checking function to use these new exceptions.
# main.py
# Import the custom exceptions from our other file
from myexceptions import NegativeAgeError, InvalidAgeTypeError
def check_age(age):
"""
Checks if an age is valid and prints a message.
Raises custom exceptions for invalid ages.
"""
print(f"\nChecking age: {age}")
# First, check the type
if not isinstance(age, int):
raise InvalidAgeTypeError(type(age).__name__)
# Then, check the value
if age < 0:
raise NegativeAgeError(age)
# If all is well, proceed
result = 100 / age
print(f"Success! 100/{age} = {result}")
def get_user_age():
"""Gets age from user and handles potential errors."""
try:
age_str = input("Please enter your age: ")
age = int(age_str)
check_age(age)
except ValueError:
print("Error: You did not enter a valid number.")
except NegativeAgeError as e:
# This will catch our specific custom exception
print(f"Custom Error Caught: {e.message} (You entered: {e.age})")
except InvalidAgeTypeError as e:
print(f"Custom Error Caught: {e.message} (You entered a: {e.age_type})")
except ZeroDivisionError:
print("Error: Age cannot be zero.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
# --- Let's run it ---
if __name__ == "__main__":
print("--- Test Case 1: Valid Age ---")
get_user_age() # Try entering 25
print("\n--- Test Case 2: Negative Age ---")
get_user_age() # Try entering -5
print("\n--- Test Case 3: Text Input ---")
get_user_age() # Try entering "hello"
print("\n--- Test Case 4: Zero Age ---")
get_user_age() # Try entering 0
Putting It All Together: A Complete Example
Here is the full code in two files, which is a common and good practice.
File 1: myexceptions.py
# myexceptions.py
class MyCustomError(Exception):
"""Base class for other custom exceptions."""
pass
class NegativeAgeError(MyCustomError):
"""Raised when an age value is negative."""
def __init__(self, age, message="Age cannot be negative"):
self.age = age
self.message = message
super().__init__(self.message)
class InvalidAgeTypeError(MyCustomError):
"""Raised when the age is not an integer."""
def __init__(self, age_type, message="Age must be an integer"):
self.age_type = age_type
self.message = message
super().__init__(self.message)
File 2: main.py
# main.py
from myexceptions import NegativeAgeError, InvalidAgeTypeError
def check_age(age):
"""Checks if an age is valid and prints a message."""
print(f"\nChecking age: {age}")
if not isinstance(age, int):
raise InvalidAgeTypeError(type(age).__name__)
if age < 0:
raise NegativeAgeError(age)
result = 100 / age
print(f"Success! 100/{age} = {result}")
def get_user_age():
"""Gets age from user and handles potential errors."""
try:
age_str = input("Please enter your age: ")
age = int(age_str)
check_age(age)
except ValueError:
print("Error: You did not enter a valid number.")
except NegativeAgeError as e:
print(f"Custom Error Caught: {e.message} (You entered: {e.age})")
except InvalidAgeTypeError as e:
print(f"Custom Error Caught: {e.message} (You entered a: {e.age_type})")
except ZeroDivisionError:
print("Error: Age cannot be zero.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__main__":
print("--- Running Age Checker ---")
get_user_age()
Key Takeaways
- Handle Errors Gracefully: Use
try...exceptto prevent your program from crashing. - Be Specific: Catch specific exceptions (
ValueError,ZeroDivisionError) before using a genericException. - Create Custom Exceptions: For better code quality, define your own exception classes by subclassing
Exception. - Make Them Informative: Add custom messages and attributes to your custom exceptions so they are easy to debug and understand.
raiseto Signal Problems: When your function encounters an invalid state,raisean exception (either built-in or custom) to signal that something went wrong.
