If my program experiences a problem reading the lines of the file, I
would like it to stop and report the error.
If you do not try
/except
you get that for free! But I guess you want
some finesse.
Thank you for including the code, the input and the output.
But I am getting both exception text’s
try:
with open('sample.txt', 'r') as reader:
for line in reader.readlines():
try:
print(int(line))
except:
print('\nLine error')
quit()
except:
print('\nError: cannot read from the file')
There are a few things to criticise here, which I’ll approach below.
The primary effect you’re seeing here is that quit()
actually quits by
raising a SystemExit
exception, which you then catch, thus the second
print. Normally we do not catch that, and therefore the exception
bubbles all the way out, and the program exits. The sys.excepthook
stuff which handles exceptions which escape knows about SystemExit
and
does something sensible. But you’re catching it yourself, which is
legal.
Criticisms:
The biggest things here are (a) that you’re using a “bare except”, which
will catch any exception including SystemExit
and (b) not reporting
what exception you’re getting, which makes this stuff a mystery to you.
At the leastm you want to print or otherwise recognise what exception
you get. For example:
try:
....
except BaseExcption as e:
print('\nError: cannot read from the file:', e)
which at least prints out the exception. You would hgave seen the
SystemExit
, whereas you probably assumed you were handling the “Line
error” exception in some form.
The same applies to the inner try
/except
: at least print the
exception there, too.
That said, there are a couple of rules or thumb for good exception
handling:
-
only handle the expected exceptions
- try to put
try
/except` around as small a piece of code as possible,
that way you have a more precise idea about where the exception really
originated
To the former: we normally write code to (a) pretend we’ve got mostly
valid data and (b) sensibly handle expected situations. That brings a
few benefits:
- the code is simpler and easier to understand and maintain
- you do what you can do, and importantly don’t try to do what you
cannot
Let’s take your int()
code:
try:
print(int(line))
except:
print('\nLine error')
quit()
This catches any problems, does not say what’s wrong, and doesn’t do any
recovery other than bailing out. Compare to this:
try:
value = int(line)
except ValueError as e:
print("the line does not seem to be an int:", e)
quit()
print(value)
This handles only a ValueError
from converting the line text to an
int
. Other exceptions are not handled, and that way you get to see
then and decide what to do about them. Note that the print()
is
outside the try
/except
.
Handling only what you know how to handle is easier, and does not
obscure what you didn’t expect, letting you decide what to do about
those additional circumstances (if anything). For example, you don’t
really want to catch SystemExit
, that stops it doing what you normally
want it to do. There’s an unbounded set of other exceptions out there,
and you don’t inherently know what to do with them either.
Cheers,
Cameron Simpson cs@cskk.id.au