Q1What does the following code print?try:
raise ValueError("NG")
print("A")
except ValueError as e:
print(e)
print("B")
Raising Exceptions with raise / Custom Exception Classes
Throw your own exceptions in Python with raise and define custom exception classes — every example runs in your browser.
In the previous article on try / except, we looked at the receiving side of an exception.
This article covers raise — the throwing side, where you surface an exception yourself. When you raise an exception on invalid input or an unexpected state, the caller is guaranteed to notice via try / except.
The basics of raise
Writing raise ExceptionClass("message") raises that exception right then. The moment raise executes, the rest of the code is skipped and control jumps to the matching except.
The message is optional, but including why it failed lets the receiver read it out via except ... as e.
# Raise a ValueError and catch it on the receiving side
try:
raise ValueError("Invalid age")
print("never reached")
except ValueError as e:
print(f"Caught: {e}")
# Output: Caught: Invalid age
# Any built-in exception works as-is
# Common ones: ValueError / TypeError / KeyError / IndexError
Validating with if + raise
raise is used most often for input validation. When an if spots something invalid, immediately raise and return the call to the caller. This is an idiomatic technique in functions (covered later), where raising inside a function notifies the caller of bad arguments.
The flow — normal path runs through; abnormal path raises and halts — is the core pattern for validation in production code.
Check the input one condition at a time; the instant something fails, raise and stop. Only when every condition passes does normal processing proceed. Since the first raise wins, the order of checks sets their priority.
# Validate a product price: 0 or below is an error
price = -500
try:
if price < 0:
raise ValueError(f"Price must be 0 or higher (got: {price})")
if not isinstance(price, int):
raise TypeError(f"Price must be an integer (got type: {type(price).__name__})")
print(f"Registered: {price}")
except ValueError as e:
print(f"Value error: {e}")
except TypeError as e:
print(f"Type error: {e}")
# Output: Value error: Price must be 0 or higher (got: -500)
A rough guide to which built-in exception to raise: use ValueError when the value is off, TypeError when the kind (type) doesn't match what's expected, and KeyError / IndexError when the target key or element is missing from a dict or list.
Defining a custom exception class
Built-in exceptions alone sometimes make it hard to tell which validation failed. Defining your own exception class lets you catch it precisely on the except side.
The shape is class ErrorName(Exception): with pass (empty) as the body — that's it. We'll cover classes in depth in the upcoming object-oriented programming chapter, but for exception classes this one line is plenty.
# Define a custom exception (1 line is enough)
class InvalidAgeError(Exception):
pass
class DuplicateUserError(Exception):
pass
registered_users = ["alice", "bob"]
new_user = "alice"
new_age = -1
try:
if new_age < 0:
raise InvalidAgeError(f"Age must be 0 or higher: {new_age}")
if new_user in registered_users:
raise DuplicateUserError(f"Already registered: {new_user}")
print(f"Registered: {new_user}")
except InvalidAgeError as e:
print(f"Age error: {e}")
except DuplicateUserError as e:
print(f"Duplicate error: {e}")
# Output: Age error: Age must be 0 or higher: -1
Custom exceptions set Exception as the parent class
The Exception in parentheses names the parent class. Putting Exception there means your custom class automatically gets the standard exception features — it can carry a message, it's catchable by a generic except Exception, and so on. The parent / child mechanism itself (inheritance) is covered in the object-oriented programming chapter, but this one line is all you need to define an exception.
In this article you learned how to raise exceptions yourself with raise, the if + raise pattern for validation, and how to define a custom exception class with Exception set as the parent.
Next up, we'll look at def — which has shown up several times already — as a first-class topic and learn how to bundle and reuse logic with functions.
Knowledge Check
Answer each question one by one.
Q2Which built-in exception is most appropriate when the value is invalid?
Q3What's the biggest benefit of using a custom exception class MyError(Exception): pass?