Raising Exceptions with raise in Python
Course: Python Training
Topic: Raising Exceptions with raise
Course Link: Python Training Course at JustAcademy
Demo Link: Register for a Course Demo
Website: Visit JustAcademy
1. Introduction to Raising Exceptions
Exception handling is an important part of Python programming. An exception represents an error or unexpected condition that occurs while a program is running. Python provides the raise statement to allow developers to deliberately trigger an exception when a particular condition is not satisfied.
For example, an application may require a user's age to be a positive number, a product price to be greater than zero, or a password to meet certain requirements. Instead of allowing invalid data to continue through the program, a developer can use raise to stop the current operation and report the problem clearly.
Raising exceptions makes programs easier to debug, maintain, and integrate with other functions and applications.
2. Learning Objectives
After completing this topic, learners will be able to:
- Understand the purpose of the
raise statement.
- Raise built-in Python exceptions manually.
- Provide meaningful exception messages.
- Use
raise with conditional statements.
- Combine raised exceptions with
try and except.
- Re-raise an exception using a bare
raise statement.
- Create and raise custom exceptions.
- Use exception chaining to preserve the cause of an error.
- Apply exception-raising techniques to practical applications.
3. What Is the raise Statement?
The raise statement tells Python to raise a specified exception. When Python encounters the statement, it creates or uses the specified exception and begins searching for an appropriate exception handler.
If a matching except block is found, that block can handle the exception. If no suitable handler is found, the exception propagates through the calling functions and may terminate the program with a traceback.
3.1 Basic Syntax
raise ExceptionType("Error message")
Here:
raise is the Python keyword used to trigger an exception.
ExceptionType is a built-in or custom exception class.
"Error message" explains why the exception occurred.
3.2 Simple Example
raise ValueError("An invalid value was provided.")
Result: Python raises a ValueError with the specified message. If the exception is not caught, Python displays a traceback.
Important: The following examples that raise exceptions outside a handler are intentionally designed to demonstrate errors. In a real application, you can catch expected exceptions when recovery is appropriate.
4. Raising Built-in Exceptions
Python provides several built-in exception classes. Developers can raise them when input or application state violates an expected rule.
| Exception |
When to Use It |
Example |
ValueError |
A value is unsuitable for the operation or violates a value requirement. |
raise ValueError("Age cannot be negative.") |
TypeError |
An object has an inappropriate type for the operation. |
raise TypeError("Expected a string.") |
ZeroDivisionError |
An operation attempts division by zero. |
raise ZeroDivisionError("Divisor cannot be zero.") |
FileNotFoundError |
An expected file cannot be found. |
raise FileNotFoundError("Configuration file is missing.") |
PermissionError |
An operation is not permitted because of insufficient permissions. |
raise PermissionError("Access is not permitted.") |
RuntimeError |
A general runtime condition prevents an operation from completing. |
raise RuntimeError("The operation cannot continue.") |
NotImplementedError |
A method or feature is intentionally left for a subclass or later implementation. |
raise NotImplementedError("Implement this method in a subclass.") |
Choose an exception type that accurately describes the problem. Avoid using a generic exception when a more specific built-in or custom exception communicates the problem better.
5. Raising ValueError for Invalid Input
ValueError is commonly used when a value has the correct general type but is outside the accepted range or does not satisfy a rule.
Example: Validating Age
def validate_age(age):
if age < 0:
raise ValueError("Age cannot be negative.")
return age
print(validate_age(25))
Output:
25
If the function receives a negative age, it raises an exception:
validate_age(-5)
Error:
ValueError: Age cannot be negative.
The function prevents invalid data from being accepted and gives the caller a clear explanation.
Example: Validating a Product Price
def calculate_discounted_price(price, discount_percent):
if price < 0:
raise ValueError("Price cannot be negative.")
if not 0 <= discount_percent <= 100:
raise ValueError("Discount must be between 0 and 100.")
discount = price * discount_percent / 100
return price - discount
print(calculate_discounted_price(1000, 10))
Output:
900.0
If the discount is 150, the function raises ValueError because the percentage is outside the accepted range.
6. Raising TypeError for Incorrect Data Types
TypeError is appropriate when a function requires a particular type of object but receives a different type that it does not support.
Example: Validating a Function Argument
def greet_user(name):
if not isinstance(name, str):
raise TypeError("Name must be a string.")
return f"Hello, {name}!"
print(greet_user("Asha"))
Output:
Hello, Asha!
Calling greet_user(123) raises:
TypeError: Name must be a string.
Type validation can make a function's expectations explicit. Use it when the function contract requires a particular type; avoid unnecessary checks when the function is intentionally designed to support multiple types.
7. Raising Exceptions with Conditional Statements
A common pattern is to check a condition and raise an exception when the condition is invalid.
Example: Checking a Bank Withdrawal
def withdraw(balance, amount):
if amount <= 0:
raise ValueError("Withdrawal amount must be positive.")
if amount > balance:
raise ValueError("Insufficient balance.")
return balance - amount
print(withdraw(5000, 1200))
Output:
3800
For a withdrawal of 6000 from a balance of 5000, the function raises ValueError with the message Insufficient balance.
Why this is useful:
- Invalid operations are rejected early.
- The function avoids returning a misleading result.
- The calling code can decide whether to display a message, retry, or cancel the operation.
8. Using raise with try and except
The raise statement can be combined with try and except. The function raises an exception when a problem occurs, while the calling code catches it and decides how to respond.
Example: Handling an Invalid Number
def square_root_input(number):
if number < 0:
raise ValueError("Number must not be negative.")
return number ** 0.5
try:
result = square_root_input(-9)
print("Square root:", result)
except ValueError as error:
print("Calculation failed:", error)
Output:
Calculation failed: Number must not be negative.
How the Code Works
- The function receives a number.
- It checks whether the number is negative.
- If the number is negative,
raise triggers a ValueError.
- Python skips the remaining statements in the
try block.
- The matching
except block catches the exception.
- The program prints a useful message instead of allowing the exception to remain unhandled.
9. Raising an Exception Without a Message
Python allows an exception class to be raised without explicitly creating an instance with a message.
raise ValueError
This is equivalent to:
raise ValueError()
Both statements raise a ValueError with no custom message. In application code, descriptive messages are usually more helpful because they explain the problem.
10. Re-Raising Exceptions with a Bare raise
A bare raise statement is used inside an active exception handler to raise the same exception again. This is useful when a function needs to log an error or perform a small amount of cleanup but still wants the caller to handle the original failure.
Example: Logging and Re-Raising
def divide_numbers(a, b):
try:
return a / b
except ZeroDivisionError:
print("A division error occurred.")
raise
try:
divide_numbers(10, 0)
except ZeroDivisionError as error:
print("Handled by the caller:", error)
Output:
A division error occurred.
Handled by the caller: division by zero
Key point: The bare raise preserves and propagates the active exception. It should normally be used while handling that exception; using it when no exception is active causes a RuntimeError.
11. Raising a New Exception from Another Exception
Sometimes a low-level exception needs to be translated into a clearer, higher-level error. Python supports exception chaining with raise ... from ..., which records the original exception as the direct cause of the new exception.
Example: Converting a Conversion Error
def read_quantity(value):
try:
quantity = int(value)
except ValueError as error:
raise ValueError("Quantity must be a whole number.") from error
if quantity < 0:
raise ValueError("Quantity cannot be negative.")
return quantity
try:
print(read_quantity("abc"))
except ValueError as error:
print("Input error:", error)
Output:
Input error: Quantity must be a whole number.
The new exception communicates the problem in the context of the application's quantity field, while the original conversion exception remains available as its cause and is shown in the traceback when the exception is unhandled.
Understanding the from Clause
raise NewException("Helpful message") from original_error
NewException is the exception that the caller receives.
original_error is the exception that caused the failure.
from explicitly links the new exception to the original cause.
You can also use raise NewException("Helpful message") from None to suppress the display of the automatically chained context. Use this carefully because hiding the context can make debugging harder.
12. Creating and Raising Custom Exceptions
Built-in exceptions cover many common situations. However, larger applications may benefit from custom exceptions that describe domain-specific problems, such as an invalid order, an unavailable account, or a failed payment.
Custom exceptions are generally created by defining a class that inherits from Exception or one of its appropriate subclasses.
Example: Custom Invalid Age Exception
class InvalidAgeError(Exception):
"""Raised when an age is outside the accepted range."""
def register_user(name, age):
if age < 18:
raise InvalidAgeError("User must be at least 18 years old.")
return f"{name} registered successfully."
try:
print(register_user("Ravi", 16))
except InvalidAgeError as error:
print("Registration failed:", error)
Output:
Registration failed: User must be at least 18 years old.
Benefits of custom exceptions:
- They represent application-specific failures clearly.
- Callers can catch a particular business error without catching unrelated exceptions.
- They make large codebases easier to understand and maintain.
- They allow related errors to be organized under a common exception hierarchy.
13. Practical Example: User Registration Validation
This example demonstrates how to raise exceptions to validate a username, email address, and password before registering a user.
class RegistrationError(Exception):
"""Base exception for registration-related errors."""
class InvalidUsernameError(RegistrationError):
"""Raised when a username is invalid."""
class InvalidEmailError(RegistrationError):
"""Raised when an email address is invalid."""
class InvalidPasswordError(RegistrationError):
"""Raised when a password is invalid."""
def register_user(username, email, password):
if not username.strip():
raise InvalidUsernameError("Username cannot be empty.")
if "@" not in email or "." not in email.split("@")[-1]:
raise InvalidEmailError("Enter a valid email address.")
if len(password) < 8:
raise InvalidPasswordError("Password must contain at least 8 characters.")
return "Registration details passed validation."
try:
message = register_user(
"learner01",
"[email protected]",
"Python123"
)
print(message)
except RegistrationError as error:
print("Registration failed:", error)
Output:
Registration details passed validation.
Note: The email check here is a simple teaching example, not a complete email validation system. Real applications should use appropriate validation libraries and secure password-handling practices.
14. Difference Between raise and try-except
| Feature |
raise |
try-except |
| Main purpose |
Triggers an exception. |
Handles exceptions raised inside the protected code. |
| Role |
Reports that an operation cannot continue under the current conditions. |
Defines how the program responds to a specified exception. |
| Example |
raise ValueError("Invalid input") |
try: ... except ValueError: ... |
| Can be used together? |
Yes. |
Yes. |
| Typical use |
Input validation, business rules, and explicit failure conditions. |
Recovery, user-friendly messages, cleanup, or error reporting. |
15. Common Mistakes When Using raise
| Mistake |
Problem |
Better Practice |
| Using a vague error message |
It is difficult to identify what failed. |
Explain which value or condition is invalid. |
| Choosing an unrelated exception type |
The exception communicates the wrong meaning. |
Use a built-in or custom exception that matches the failure. |
| Raising an exception without handling it where recovery is expected |
The program may terminate unexpectedly. |
Catch the exception at an appropriate level when recovery is possible. |
| Using bare raise outside an active handler |
Python raises a RuntimeError. |
Use bare raise inside an exception handler. |
| Replacing an exception without preserving useful context |
The original cause may be harder to diagnose. |
Use raise NewError(...) from error when translating an exception. |
| Using exceptions for ordinary control flow |
The code becomes harder to follow. |
Use conditions and return values for expected routine outcomes; raise exceptions for exceptional or invalid conditions. |
| Catching every exception and ignoring it |
Real defects may remain hidden. |
Catch specific exceptions and report or handle them appropriately. |
16. Best Practices for Raising Exceptions
- Use exception types that accurately describe the problem.
- Include concise, meaningful messages that help developers or callers understand the failure.
- Validate arguments at appropriate boundaries, such as public function inputs.
- Raise exceptions early when continuing would produce an invalid or misleading result.
- Catch exceptions at a level where a useful recovery action can be taken.
- Use bare
raise when you need to propagate the active exception after logging or performing necessary work.
- Use exception chaining to preserve the original cause when translating low-level failures into application-specific errors.
- Create custom exceptions when they clarify important business rules or application behavior.
- Avoid exposing passwords, authentication tokens, personal information, or other secrets in exception messages and logs.
- Test both valid inputs and conditions that should trigger exceptions.
17. Practice Exercises
Exercise 1: Validate Age
Write a function named check_age(age) that raises ValueError when the age is negative and returns the age otherwise.
Exercise 2: Validate a Division Operation
Create a function that accepts two numbers and raises ZeroDivisionError if the second number is zero.
Exercise 3: Validate a Password
Write a function that raises ValueError if a password contains fewer than eight characters.
Exercise 4: Re-Raise an Exception
Create a function that catches a ValueError, prints a diagnostic message, and uses a bare raise to pass the original exception to its caller.
Exercise 5: Create a Custom Exception
Define an InsufficientBalanceError class and use it when a bank withdrawal exceeds the available balance.
18. Mini Project: Bank Account with Custom Exceptions
Objective: Build a simple bank account system that validates deposits and withdrawals using the raise statement.
Requirements:
- Reject zero or negative deposits.
- Reject zero or negative withdrawal amounts.
- Raise a custom exception when the withdrawal exceeds the balance.
- Display the updated balance after successful transactions.
- Handle expected exceptions in the main program.
Sample solution:
class InsufficientBalanceError(Exception):
"""Raised when a withdrawal exceeds the available balance."""
class BankAccount:
def __init__(self, balance=0):
if balance < 0:
raise ValueError("Opening balance cannot be negative.")
self.balance = balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("Deposit amount must be positive.")
self.balance += amount
return self.balance
def withdraw(self, amount):
if amount <= 0:
raise ValueError("Withdrawal amount must be positive.")
if amount > self.balance:
raise InsufficientBalanceError("Insufficient account balance.")
self.balance -= amount
return self.balance
account = BankAccount(1000)
try:
account.deposit(500)
print("Balance after deposit:", account.balance)
account.withdraw(2000)
print("Balance after withdrawal:", account.balance)
except (ValueError, InsufficientBalanceError) as error:
print("Transaction failed:", error)
Output:
Balance after deposit: 1500
Transaction failed: Insufficient account balance.
The example demonstrates how exceptions protect the account from invalid transactions and allow the calling code to respond to errors without embedding all error-handling logic inside each method.
19. Interview Questions and Answers
Q1. What is the purpose of the raise statement in Python?
The raise statement explicitly triggers an exception when a program encounters an invalid value, an unmet requirement, or another condition that prevents an operation from continuing.
Q2. Can we raise built-in exceptions manually?
Yes. For example, raise ValueError("Invalid input") raises a built-in exception with a descriptive message.
Q3. What is the difference between raise ValueError and raise ValueError("Invalid input")?
Both raise a ValueError, but the second supplies a custom message that explains the problem.
Q4. What does a bare raise statement do?
Inside an active exception handler, a bare raise re-raises the exception currently being handled.
Q5. Can we use raise with try-except?
Yes. A function can raise an exception, and the calling code can catch it using a matching except clause.
Q6. What is exception chaining?
Exception chaining preserves the relationship between an original exception and a new exception. The syntax raise NewError("Message") from error identifies the original exception as the direct cause.
Q7. Why create custom exceptions?
Custom exceptions represent application-specific problems and allow callers to handle those problems separately from unrelated built-in exceptions.
Q8. What happens if a raised exception is not handled?
The exception propagates through the calling code. If it remains unhandled, Python typically displays a traceback and terminates the affected program execution.
Q9. When should ValueError be used?
Use ValueError when a value is unsuitable or violates a value-related requirement, such as a negative quantity where only non-negative values are accepted.
Q10. Should exceptions be used for every condition?
No. Use normal conditional statements and return values for routine outcomes. Raise exceptions when an operation violates its contract or cannot proceed as expected.
20. Quick Revision Checklist
raise explicitly triggers an exception.
- Built-in exceptions include
ValueError, TypeError, and ZeroDivisionError.
- Exception messages should clearly explain the problem.
- Use conditions to determine when an exception should be raised.
- Use
try and except to handle expected exceptions.
- A bare
raise re-raises the active exception inside a handler.
raise NewError(...) from error preserves the direct cause of a new exception.
- Custom exceptions help describe application-specific failures.
- Choose exception types that match the actual problem.
- Test both normal and invalid input cases.
21. Conclusion
The raise statement gives Python developers explicit control over error reporting. It helps validate inputs, enforce business rules, prevent invalid operations, and communicate failures to the code responsible for handling them.
By combining raise with built-in exceptions, custom exception classes, try/except, and exception chaining, developers can create applications that are more predictable, maintainable, and easier to debug.
22. Additional Learning Resources
Read the official Python documentation on errors and exceptions to learn more about raising, handling, and chaining exceptions.
Explore the Python Training Course at JustAcademy, register for a course demo, or visit the JustAcademy homepage for more learning opportunities.