[Python-ideas] Extending error handling on with statements.
Steven D'Aprano
steve at pearwood.info
Mon Mar 28 00:40:17 CEST 2011
Jakob Bowyer wrote:
> I personally love using with statements when handling file like objects.
> This is all well and good until an exception is thrown from the with
> statement. This is ok if you expect the exception because you can use try
You should always expect an exception when doing file I/O.
> and except but personally I feel that another condition to with would feel
> more 'pythonic' this means that you could fail the with statement with an
> exception jump to the clause, then jump back to the with statement trying
> the code in the clause e.g. rather than
>
> try:
> with open('nofile.txt','r') as inp:
> #nofile.txt does not exist and throws an exception
> except IOError:
> with open('another.txt','r') as inp:
> #carry on where you left off...
>
> You could simply have
>
> with open('nofile.txt','r') as inp:
> #exception here
> else:
> #give a new file to the with statement here and/or run some panic code
> where your program does something to fix the situation.
You say "jump back to the with statement", and "give a new file to the
with statement". It sounds like you are thinking of turning with into a
looping construct, e.g. this BASIC-like pseudo-code:
10 somefile = 'nofile.txt')
20 with open(somefile, 'r') as inp:
...
70 else:
# Try again with a new file.
80 somefile = 'a different file.txt'
90 goto 20
The obvious problem with this is obvious: if the *second* file also
fails to open, you will loop forever as the handler jumps to the `else`
clause, sets the same name, and returns to try the with statement again.
This will be an annoying source of errors. I don't know if I like this
idea: I can see that it can be useful to repeat a block if an error
occurs, but I think that it needs to be more obvious that you are looping.
You also seem to be assuming that the only error that will be caught
will be "file not found" type errors. The beauty of a try-except block
is that you can have different handlers depending on the error:
somefile = 42 # Oops!
try:
with open(somefile, 'r') as inp:
...
except TypeError:
handle_filename_not_a_string()
Your suggested `else` clause loses all information about what sort of
error occurs, as well as where:
outfile = 'output.txt'
with open(outfile, 'w') as out:
out.write(42) # Oops!
else:
# Try another file.
outfile = 'another file.txt'
Lastly, your suggested syntax would be confusing. In try blocks, the
`else` clause runs when there is no error. In with blocks, it would run
when there is an error. That's not helpful: things that look similar
should be similar.
Of course, you can fix this problem by changing the with statement to
use `except` clauses:
with open(fname) as f:
...
except TypeError:
...
except IOError as e:
...
else: # no error
...
but this adds much complexity to the with statement, and except for the
magic goto, you can already do that at the cost of one line and one
indent level:
try:
with open(fname) as f:
...
except TypeError:
...
except IOError as e:
...
else: # no error
...
Saving one indent level and a line doesn't seem important enough for new
syntax, especially new syntax which essentially duplicates functionality
that already exists.
--
Steven
More information about the Python-ideas
mailing list