AI Hints
Home›Python Tutorial›Files, Errors and Modules
Python · Lesson 14 of 49

Handling Errors

Stay calm when things go wrong.

⏱ 2 min read▶ Video at 45:10🎓 Free
Watch this lesson in the Python courseWatch on YouTube ↗Full Python course

Ava's program asks a customer for a quantity. The customer types, two, with letters, instead of a number. The program crashes, with a scary red message, in front of the customer. Real programs must expect trouble, like bad input and missing files, and deal with it gracefully. Python gives us exceptions.

Handling Errors
From the video: Handling Errors
  • Real programs meet bad input
  • A crash is a bad experience
  • Exceptions let us react calmly

Meet some errors

Let's see common errors. Dividing by zero raises ZeroDivisionError. Converting letters to a number raises ValueError. Asking a list for an item that does not exist raises IndexError, and a dictionary raises KeyError. An error message tells you the type, and where it happened. Read it from the bottom up.

10 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
int("two")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'two'
[1, 2, 3][5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
{"a": 1}["b"]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'b'
"x" + 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str

try and except

Wrap risky code in a try block. If an error happens, Python jumps to the matching except block, instead of crashing. The program carries on. Here, Ava converts the customer's text. A bad answer is caught, and a friendly message appears, instead of a crash.

try1.pypython
text = "two"
try:
    qty = int(text)
    print("Quantity:", qty)
except ValueError:
    print("Please type digits, like 2")
print("The program keeps running")
Output
Please type digits, like 2
The program keeps running

else, finally and several excepts

You can catch different errors differently. The else block runs only when nothing went wrong. The finally block runs always, success or failure, which is perfect for cleanup. Catch the specific errors you expect, and avoid a bare except, because it hides real bugs.

try2.pypython
def load(name):
    try:
        f = open(name)
    except FileNotFoundError:
        print("Missing file:", name)
    except PermissionError:
        print("No permission")
    else:
        print("Loaded", name)
        f.close()
    finally:
        print("Done with", name)

load("orders.txt")
load("nope.txt")
Output
Loaded orders.txt
Done with orders.txt
Missing file: nope.txt
Done with nope.txt
Also uses orders.txt
fern, 2

Raising your own errors

You can raise an exception yourself, when something is wrong, using the raise keyword. This is how a function refuses bad input, with a clear message. Callers can then catch it. Choose the right type, like ValueError for a bad value. Here the quantity must be positive.

raise.pypython
def order(qty):
    if qty <= 0:
        raise ValueError("Quantity must be positive")
    return f"Ordering {qty}"

print(order(3))
try:
    print(order(-1))
except ValueError as e:
    print("Rejected:", e)
Output
Ordering 3
Rejected: Quantity must be positive

A retry loop for input

Now combine loops and errors, for a robust input routine. The loop keeps asking until the answer is valid. A valid answer ends the loop with break. A bad one is caught, and the user is asked again. Customers can type anything, and the program stays calm.

retry.pypython
while True:
    text = input("How many plants? ")
    try:
        qty = int(text)
        break
    except ValueError:
        print("Digits only, please.")
print("Got it:", qty)
Input typed: two · 2.5 · 4
Output
How many plants? two
Digits only, please.
How many plants? 2.5
Digits only, please.
How many plants? 4
Got it: 4

Reading a traceback

When an error is not caught, Python prints a traceback. Read it from the bottom. The last line tells you the error type and message. The lines above show the path of calls that led there, with file names and line numbers. Look for your own file, and fix that line. A traceback is not an attack, it is a friendly map.

Last line firsterror type and message
Follow the file namesfind your own code
Line numberswhere it happened
Stay calmit points straight at the problem

A safe divider

Your turn. Write a function that divides two numbers. If the second is zero, it should print, Cannot divide by zero, and return None. Use try and except. Ready? Here is one solution. The try holds the division, and the except catches ZeroDivisionError.

✍️ Exercise: A safe divider

Write safe_divide(a, b) that returns a / b, but prints a message and returns None on division by zero.

Show hint

catch ZeroDivisionError

Show solution
safe_div.pypython
def safe_divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        print("Cannot divide by zero")
        return None

print(safe_divide(10, 4))
print(safe_divide(1, 0))
Output
2.5
Cannot divide by zero
None

Summary

Nice work. Your programs can now survive bad input. You use try and except, with else and finally, you raise your own errors, and you read tracebacks from the bottom up. Next, Ava splits her growing program into modules, and installs packages from the internet.

Key takeaways
  • try / except / else / finally
  • Catch specific exceptions
  • raise your own errors
Next up: Modules and Packages — organise code, and borrow from the world