"Try:" which only encompasses head of compound statement

Carl Banks pavlovevidence at gmail.com
Mon Aug 27 19:21:43 EDT 2007


On Aug 27, 5:35 pm, Jameson.Qu... at gmail.com wrote:
> I have:
>
> try:
>     for line in open(myFileName):
>         count += 1
> except IOError:
>     print "Can't open myfile"
>
> (I know, this is bad, I never close the file, but its just for
> illustration). But then I change it to:
>
> try:
>     for line in open(myFileName):
>         count += openAndProcessSubfile(line)
> except IOError:
>     print "Can't open myfile"
>
> ... now the 'except' incorrectly catches errors from
> openAndProcessSubfile.
> Of course, I can always do:
>
> try:
>     myFile = open(myFileName)
> except IOError:
>     print "Can't open myfile"
> for line in myFile:
>     count += openAndProcessSubfile(line)
>
> ...But if my compound statement is "with" instead of "for" that seems
> to defeat the purpose:
>
> try:
>     myFile = open(myFileName)
> except IOError:
>     print "Can't open myfile"
> with myFile as anotherNameForMyFile:
>     ....


I suspect this isn't often complained about because this usage of
try...except kind of misses the boat.  The above treats the exception
as nothing more than an error return code, but it's often not optimal
to handle error so close to the call.

The best reason to catch and handle an exception very close to the
call is if you intend to recover from it right away.  For example:

try:
    f = open("fileA")
except IOError:
    f = open("fileB")

If you don't intend to recover right away, it's usually better to let
the exception propogate until up the call chain until the point where
you do want to recover.

Consider this: is there any other code in your program that has to do
something different based on whether you successfully opened this file
or not?  If so, how will you notify it whether the call has succeeded
or not?  Very often, the caller itself needs to know.  You could, say,
set a flag to indicate it's failed, but why do that when you could
simply let the caller detect and handle the error itself?

If you don't intend to recover at all, you should let it propogate up
to the point where you will resume normal processing (for example:
before the next input prompt), and handle it there.  Especially if
you're going to print an error message: printing an error message at
the point the error occurs can severely limit code reusability.


Enough rambling.  Here's what I'd do in your situation: nothing.
Don't handle the exception here at all.  Let it raise IOError.  My
code would look like this:

with open('myFile') as myFile:
    ....

However, I would handle the exeption wherever I intended to take
action based on success or failure.  It looks like you are treating
"file-not-found" as non-fatal, and other IOErrors as fatal?  In that
case, we would have to check the error code to distinguish, and
reraise if not file not found.

# this is the point where success or failure
# determines what I do next, that's why I handle
# the exception here.
try:
    load_myFile()
except IOError, e:
    if e.errno == 2:  # file not found is usually errno 2
        print "file not found"
    else:
        raise
else:
    # load succeeded, do whatever.


One other useful technique is recasting: catching an error close to
the call, and raising a different error.


Carl Banks




More information about the Python-list mailing list