Python Arena
Step 3 of 5

Different kinds of errors

Each kind of error has its own exception, and its name tells what went wrong. Here are the ones you'll meet most often, in the Python interpreter:

In the Python interpreter
>>> int("3.5")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '3.5'
>>> "Age: " + 30
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str
>>> [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'
>>> 10 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
  • ValueError: a value of the right type, but with contents that don't work. int("3.5") gets a string, as it should, but not one that's a whole number; float("twelve") fails the same way.
  • TypeError: a value of the wrong type for what the code does with it, such as adding a number to a string, or repeating a string by a string, "ab" * "3".
  • IndexError: an index that a list or a string doesn't have.
  • KeyError: a key that a dictionary doesn't have.
  • ZeroDivisionError: dividing by zero, with /, // or %. The zero usually comes from data: a number the user typed, or one read from a file.
  • FileNotFoundError: opening a file that doesn't exist. (Its cousin PermissionError comes when the file is there but the program may not use it, such as a file that belongs to another user of the computer.)

Several except blocks

One try can have several except blocks, one for each kind of error it is ready for. Python checks them in order and runs the first one that matches. Only one of them runs:

colors = ["red", "green", "blue"]
try:
    index = int(input("Which color (0-2)? "))
    print("You picked", colors[index])
except ValueError:
    print("That's not a number.")
except IndexError:
    print("There's no color with that number.")
Input
5
Output
Which color (0-2)? 5
There's no color with that number.

A missing file is handled the same way. Print a message of your own that says what happened:

try:
    with open("settings.txt") as file:
        print(file.read())
except FileNotFoundError:
    print("No settings.txt, using the default settings.")
Output
No settings.txt, using the default settings.

A bare except hides mistakes

except: without a name catches every exception there is. That's tempting, but it can't tell the user's mistakes from the program's own. This program has a bug: the days are numbered from 1, but list indexes start at 0, so it should look up days[number - 1]:

days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
try:
    number = int(input("Day number (1-7): "))
    print("That's", days[number])
except:
    print("Please type a number from 1 to 7.")
Input
7
Output
Day number (1-7): 7
Please type a number from 1 to 7.

The user did type a number from 1 to 7. days[7] raised an IndexError, and the bare except turned the program's bug into a message that blames the user. Name the exception you expect from the user instead, here ValueError, and the bug shows itself:

days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
try:
    number = int(input("Day number (1-7): "))
    print("That's", days[number])
except ValueError:
    print("Please type a number from 1 to 7.")
Input
7
Output
Day number (1-7): 7
Python stops with
Traceback (most recent call last):
  File "main.py", line 4, in <module>
    print("That's", days[number])
                    ~~~~^^^^^^^^
IndexError: list index out of range

The traceback names the line with the wrong index. So catch only the exceptions you expect, and let real bugs show their traceback.

Your task

Challenge 1 of 3

What does this program print? Type each line it prints.

Challenge 2

Write a program that asks for the name of a file of numbers, one per line, and prints their average. It must not crash, whatever the file:

  • a file that doesn't exist: print No file called and the name;
  • a line that isn't a number: print The file has a line that isn't a number;
  • an empty file (no numbers, so the average divides by zero): print The file is empty.

With this weights.txt

70
73

a run looks like this:

File: weights.txt
Average: 71.5

Challenge 3

Write a function to_minutes(text) that turns a time like 08:30 into the number of minutes since midnight (here 510). If the text isn't a valid time, it returns -1 instead. Invalid texts include 8h30 (no colon, so the split gives only one piece), ab:30 (not numbers), 24:00 and 12:60 (hours must be 0 to 23 and minutes 0 to 59).

Let int and the index raise their exceptions, and catch them, instead of checking every character yourself.

For example, to_minutes("08:30") returns 510 and to_minutes("8h30") returns -1.