Python Try ... Except
When something goes wrong while a program runs, Python raises an exception: dividing by zero raises ZeroDivisionError, converting "ten" with int raises ValueError, opening a missing file raises FileNotFoundError. If nothing handles the exception, the program stops with a traceback. With try and except, the program can catch the exception and react sensibly instead.
try and except
Put the code that might fail in a try block, and what to do on failure in an except block:
for text in ["42", "ten", "7"]:
try:
number = int(text)
print(text, "->", number * 2)
except ValueError:
print(text, "is not a whole number")42 -> 84 ten is not a whole number 7 -> 14
When a line in the try block raises the exception, the rest of the block is skipped and the matching except block runs. Then the program carries on after the whole statement.
Several kinds of errors
Name the exceptions you expect. One try can have several except blocks, and as gives you the exception itself, whose message you can print:
def divide(a, b):
try:
return a / b
except ZeroDivisionError:
return "cannot divide by zero"
except TypeError as e:
return f"wrong types: {e}"
print(divide(10, 4))
print(divide(1, 0))
print(divide("10", 2))2.5 cannot divide by zero wrong types: unsupported operand type(s) for /: 'str' and 'int'
Avoid a bare except: that catches everything: it also hides mistakes you did not expect, such as a misspelt variable name, and makes bugs hard to find.
else and finally
An else block runs when no exception happened; a finally block always runs, error or not, and is the place for clean-up such as closing a file:
while True:
try:
age = int(input("Your age: "))
except ValueError:
print("Please type a number.")
else:
print("Thank you, age", age)
break
finally:
print("(checked one answer)")twenty 20
Your age: Please type a number. (checked one answer) Your age: Thank you, age 20 (checked one answer)
This loop is the standard way to ask until the input is valid.
Raising exceptions
Your own functions can raise exceptions with raise when they receive values they cannot handle. You can also define your own exception classes by inheriting from Exception:
class InsufficientFunds(Exception):
pass
def withdraw(balance, amount):
if amount <= 0:
raise ValueError("the amount must be positive")
if amount > balance:
raise InsufficientFunds(f"only {balance} available")
return balance - amount
for amount in [300, -5, 900]:
try:
print("New balance:", withdraw(500, amount))
except (ValueError, InsufficientFunds) as e:
print(f"{type(e).__name__}: {e}")New balance: 200 ValueError: the amount must be positive InsufficientFunds: only 500 available
Practice exercises
- Ask for two numbers and divide them, printing a friendly message for division by zero and for input that is not a number.
- Try to open a file that does not exist and catch
FileNotFoundError. - Write a function
square_root(x)that raisesValueErrorfor negative numbers, and call it insidetry. - Add a
finallyblock to one of your programs that prints "Goodbye".