What types of exceptions should you catch? - Python Morsels
Show captions
Autoplay
Auto-expand
Sign in to change your settings
Sign in to your Python Morsels account to save your screencast settings.
Don't have an account yet? Sign up here.
What types of exceptions should you catch?
Catching many exceptions at once
When catching an exception, it's generally considered a good idea to only catch exceptions if you understand their origin .
Here we have some code that catches many exception types at once.<br>We're catching a ValueError, a TypeError, a KeyError, and a NameError exception:
import csv<br>import datetime<br>import sys
def parse_date(date_string):<br>return datetime.date.fromisoformat(date_string)
[filename] = sys.argv[1:]<br>with open(filename) as csv_file:<br>reader = csv.DictReader(csv_file)<br>for n, row in enumerate(reader, start=1):<br>name = row["name"]<br>try:<br>start, end = parse_date(row["start"]), parse_date(row["end"])<br>except (ValueError, TypeError, KeyError, NameError) as e:<br>error = type(e).__name__<br>print(f"{error}: Invalid date on line {n}", file=sys.stderr)<br>continue<br>time = end - start<br>print(f"{name}: {time.days} days")
It's not entirely clear why it catches each of these types of exceptions.
When will a NameError be raised?
We probably shouldn't be catching a NameError exception at all because NameError exceptions are usually raised when a variable name has been misspelled.<br>Catching a NameError wouldn't catch a bug in data from an end user; it would suppress a bug in our code !
So we will stop catching a NameError exception immediately.
except (ValueError, TypeError, KeyError) as e:
When will a ValueError be raised?
A ValueError exception can be raised if our CSV file has some invalid data in it, specifically if any of our rows contains an invalid date.
For example this CSV file has an invalid date (2026-00-01) on line 4:
name,start,end<br>2021-Q1,2025-01-01,2025-04-01<br>2021-Q2,2025-04-01,2025-07-01<br>2021-Q3,2025-07-01,2025-10-01<br>2021-Q4,2025-10-01,2026-00-01
And when we run our program against it, a ValueError is raised:
$ python3 find_data_periods.py data1.csv<br>2021-Q1: 90 days<br>2021-Q2: 91 days<br>2021-Q3: 92 days<br>ValueError: Invalid date on line 4
When will a TypeError be raised?
If we have missing dates in our CSV file a TypeError will be raised.
We have a couple of rows in our CSV file that simply don't have some columns:
name,start,end<br>2021-Q1,2025-01-01,2025-04-01<br>2021-Q2<br>2021-Q3,2025-07-01,2025-10-01<br>2021-Q4,2025-10-01
The start and end columns are missing on some rows in this file, so a TypeError is raised:
$ python3 find_data_periods.py data2.csv<br>2021-Q1: 90 days<br>TypeError: Invalid date on line 2<br>2021-Q3: 92 days<br>TypeError: Invalid date on line 4
When will a KeyError be raised?
A KeyError is raised in kind of an odd situation: if our CSV file has a typo in a header a KeyError will be raised.
The column start is misspelled in this CSV file (it has an uppercase S instead of lowercase s):
name,Start,end<br>2021-Q1,2025-01-01,2025-04-01<br>2021-Q2,2025-04-01,2025-07-01<br>2021-Q3,2025-07-01,2025-10-01<br>2021-Q4,2025-10-01,2026-01-01
When we run our program against this file, it seems like there's a problem in every row in our file:
$ python3 find_data_periods.py data3.csv<br>KeyError: Invalid date on line 1<br>KeyError: Invalid date on line 2<br>KeyError: Invalid date on line 3<br>KeyError: Invalid date on line 4
But there's not really.<br>The problem is just really with our header.
So it might actually be better if we didn't catch a KeyError exception at all .<br>Because the traceback that would be shown to the end user would actually be more clear in this case.
$ python3 find_data_periods.py data3.csv<br>Traceback (most recent call last):<br>File "/home/trey/find_data_periods.py", line 14, in<br>start, end = parse_date(row["start"]), parse_date(row["end"])<br>KeyError: 'start'
Tracebacks are never pretty, but at least this one shows that there's a problem involving the word start.<br>A user could hopefully figure out from this that the lowercase s in the traceback and the uppercase S in our CSV file are mismatched.
This traceback isn't particularly clear, but it is more clear than the error message we were showing before.<br>Sometimes exceptions are better left unhandled.
Handling problems preemptively
Instead of not catching a KeyError at all, we could handle this problem in our headers before we even start looping .<br>Remember, the issue isn't with each row in our file: the problem is just with the first row.
So we'll check our headers line for missing headers.<br>If we have a missing header, we'll print out an error message and then exit our program .
import csv<br>import datetime<br>import sys
def parse_date(date_string):<br>return datetime.date.fromisoformat(date_string)
[filename] = sys.argv[1:]<br>with open(filename) as csv_file:<br>reader = csv.DictReader(csv_file)<br>for header in ["name", "start", "end"]:<br>if header not in reader.fieldnames:<br>print(f"Error: Missing {header} header", file=sys.stderr)<br>sys.exit(1)<br>for n, row in...