Introduction
Catching errors is half the story. Your own functions should also raise errors when they are given something they cannot handle, so the problem is reported clearly at the place it starts.
A function that quietly returns a wrong value causes confusing errors far away from the real problem. Raising an error at once puts the report right where the mistake happened, and lets the caller decide what to do about it.
How it works
raise
def set_age(age):
if age < 0:
raise ValueError("age cannot be negative")
return age
print(set_age(20))
print(set_age(-3))set_age(20) works. set_age(-3) reaches raise ValueError(...), and the program stops with that message, pointing at line 3. Raising early is better than returning a wrong value that causes a confusing error much later.
finally
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide")
finally:
print("Done either way")A finally block runs whether or not an error happened. It is the place for clean-up, such as closing a file or a connection.
Syntax
class TooLow(Exception):
pass
def check(x):
if x < 0:
raise TooLow("x must not be negative")
return x
Example
class InsufficientFunds(Exception):
pass
def withdraw(balance, amount):
if amount > balance:
raise InsufficientFunds(f"need {amount - balance} more")
return balance - amount
try:
withdraw(100, 250)
except InsufficientFunds as error:
print("Refused:", error)class InsufficientFunds(Exception): pass creates a new kind of error. The caller can catch exactly that kind with except InsufficientFunds as error, and error holds the message you passed in: need 150 more.
Line by line
class InsufficientFunds(Exception): passmakes a new kind of error.withdrawraises it when the amount is larger than the balance.- The message says how much more is needed.
- The call on the
tryline asks for 250 from a balance of 100, so the error is raised. except InsufficientFunds as errorcatches it, anderrorholds the message.
Expected result
Refused: need 150 more
In the real world
Libraries raise specific errors so that callers can respond correctly, such as asking a user to log in again after an expired session. Web frameworks turn such errors into the right response for the browser.
Common mistakes
- Raising a vague error: prefer a specific type (
ValueError,TypeError) and a message that says what was wrong. - Writing
raise ValueErrorand catchingExceptioneverywhere, which hides real bugs. - Using exceptions for normal control flow, such as ending a loop; use
ifandbreak.
Best practices
- Use the most specific error type that fits.
- Say what was wrong in the message, and what was expected.
- Make a custom exception when callers need to tell it apart.
Summary
raise reports a problem at the place it is found. A class that inherits from Exception creates your own kind of error, and finally runs whether or not an error happened.
Practice
Write parse_mark(text) that converts text to an int and raises ValueError("mark must be 0 to 100") when the number is out of range. Call it inside try with good and bad inputs.
Quick check
Key takeaways
- Raise as soon as you know something is wrong.
- A clear message is half of the fix.
- finally is the place for clean-up.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.