Programming and IT
Python: exceptions
An exception is a signal that execution went differently from what the code expected. By default it stops the program and prints a traceback. A `try/except` block lets you catch only the error you anticipated and carry on, without hiding real breakages.
In this article
What an error looks like and what to read in it#
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# ValueError: invalid literal for int() with base 10: 'hundred'
Two things matter in a traceback: the last line — the error type and message — and the lines above it, which show the path that led there. Read it from the bottom up: first what happened, then where.
Exception types form a tree. Almost everything you catch in application code
inherits from Exception:
ValueError— the type is right, the value is not (int("hundred"));TypeError— the type is wrong ("a" + 1);KeyErrorandIndexError— no such key or index;ZeroDivisionError— division by zero;FileNotFoundError— no such file;AttributeError— the object has no such attribute.
try/except: the minimum#
=
= 0
The try block holds only the risky line — the shorter it is, the clearer it is
what exactly is protected. You can list several types, and the error object
itself is available through as:
=
# KeyError — 'b'
Several except blocks are checked from top to bottom, and the first matching
one runs. That is why specific types go above general ones: an except Exception
placed first catches everything, and the rest never get a chance.
else and finally#
=
# only if there was no exception
# parsed: 42
# this block always runs
else runs when try finished without errors — put code there that should not
be covered by this except. finally runs no matter what: on an error, on a
return, and when an exception propagates further. It is where you release
resources — although for files and connections the with statement is handier,
as described in the article on reading files in Python.
raise and your own error classes#
Raising an exception yourself takes one line. It is the right way to report
invalid arguments: a function should not silently return None.
return -
# refused: amount must be positive, got -5
When the built-in types are not enough, you define your own — usually as an empty class:
"""The settings are invalid."""
# the settings have no host key
To catch an error and re-raise it while keeping the cause, use raise ... from:
raise ConfigError("could not read") from error — both exceptions stay in the
traceback, and you can see which one was the root cause.
What not to do#
A bare except:. Such a block catches absolutely everything, including
KeyboardInterrupt and SystemExit — the program can no longer be stopped from
the keyboard. If you need a wide net, write except Exception, and preferably
report what happened.
except ...: pass. A silently swallowed error comes back an hour later as an
empty report, and there is nothing left to trace it with. At the very least, print
it or write it to a log.
A huge try. When there are twenty lines under try, except ValueError
applies to all twenty, and you will catch an error somewhere you did not expect.
Exceptions instead of conditions. A check like if x > 0 does not need try.
But the opposite extreme is harmful too: Python favours trying and catching over
asking first — d.get(key) or try/except KeyError beats if key in d before
every access when there are many accesses.
Practice: write a function safe_div(a, b) that returns the quotient, or None
with a message on division by zero; then a function parse_ages(strings) that
turns a list of strings into numbers, skipping non-numeric ones and reporting each
skip. You will need Python lists and
Python functions.
Step-by-step plan
- Read a tracebackRun int("hundred") and take the output apart: type, message, location.
- Your first try/exceptProtect a string-to-number conversion and print a clear message instead of crashing.
- Several typesCatch KeyError and ZeroDivisionError in one block and print the error type with type(error).__name__.
- Add finallyMake sure the finally block runs both with and without an error.
- Your own error classDefine a subclass of Exception, raise it from a function and catch it in the calling code.
Start learning this in your own space
The plan goes into your repository: tick off stages, keep notes — the change history shows how far you have come.
Check yourself
1.Which exception type does int("hundred") raise?
2.try: x = 1 / 0 / except ZeroDivisionError: x = 7 / finally: x += 1 — what is x?
3.Which block runs only when there was no exception in try?
4.What is wrong with a bare except: without a type?
Sources
-
Errors and Exceptions in the Python tutorialtry, except, else, finally and raise with examplesfree
-
Built-in ExceptionsThe full type tree: what inherits from whatfree
-
Exercism — Python trackFree Python exercises with automated testsfree
Was this helpful?