A little disappointed so far

Tom Bryan tbryan at python.net
Tue May 20 08:31:43 EDT 2003


Graham Nicholls wrote:

>> But Alex will probably trundle by in a moment to tell you that in many
>> cases, you don't want to do that.  Python's powerful exception handling
>> system means that most of the time you just do:
>> 
>> try:
>>     f = file(filename)
>> except IOError:
>>     <handle exception>
>> 
> I guess thats reasonably succinct.
> 
>> Thing is, no matter how much you test, there's always the possibility of
>> a race condition that prevents you from opening a file.  I'll note that
>> since you're mostly doing shell script equivalents, it's more likely
>> that you'll want to do the tests (because you want to know whether
>> something is a file or a directory).
> 
> I suppose so, unless you've some sort of temporary file creation function.
> So, generally is it the "Python Way" to try things and handle the
> exceptions, as in try... except, or to run os.path.isfile ?
> Are there good reasons for this? 

One thing it permits you to do is bubble up errors to the appropriate place.  
In another reply, I mention that I ended up bundling up a bunch of code 
into reusable functions and module in Python.  While 

open(FILE, $filename) || die "Couldn't open file $filename"

may be fine, succint, and charmingly readable in a flat script, you probably 
don't want it buried down in four layers of functions calls.  For example, 
if I need a config file, I may write a little config file parser.  
(Actually, I'd just use Python's ConfigParser module...proper impatience is 
one of the three virtues in the Perl crowd, right?)  Now, if I  require the 
config file to be present, the config file parser will attempt to open the 
specified file and get an IOError.  I certainly don't want the config file 
parser to exit for me.  That might be fine for the first program that used 
it, but I may be able to recover from that error in another program.  
Better to throw the exception up and deal with it at a higher level.  (Of 
course, now you're faced with the complication of deciding which errors you 
need to handle at a higher level.)

This whole long-winded explanation is trying to say that 

try:
    f = file(filename)
    # ...do 20 lines of work
except IOError:
    <handle exception>

can be bundled up into a function in two ways
# move all of the code to a function
def foo(filename):
    try:
        f = file(filename)
        # ...do 20 lines of work
    except IOError:
        <handle exception>

# later, in your main code, call the function
foo()


OR

# move just the work to a function
def foo(filename):
    """foo(ffilename) -> explanation of results
    Throws an IOError if the filename is not a readable file."""
    f = file(filename)
    #...do 10 lines of work

# later, in your main code, call the function
try:
    foo()
    #...the remaining 10 lines of work
except IOError:
    <handle exception>

So, one nice thing about exceptions is that you can bundle behavior for 
later while leavnig some of the error handling at the top level.  It's a 
simple example, but I think that it makes the point.  Like I said, this 
choice adds some complexity in figuring out which exceptions to throw and 
handle at which levels.  But as you start to build up a bunch of modules 
that you use in your code, you'd like the leave the code at the top level 
in control of when to exit.  It's much better than calling foo,  which 
calls bar, which calls baz, which instantiates a class and calls a method 
that exits the entire program.  :-)

---Tom





More information about the Python-list mailing list