Steve Holden wrote: > Simon Willison wrote: > >>Hi all, >> >>I have an API design question. I'm writing a function that can either >>succeed or fail. Most of the time the code calling the function won't >>care about the reason for the failure, but very occasionally it will. >> >>I can see a number of ways of doing this, but none of them feel >>aesthetically pleasing: >> >>1. >> >>try: >> do_something() >>except HttpError: >> # An HTTP error occurred >>except ApplicationError: >> # An application error occurred >>else: >> # It worked! >> >>This does the job fine, but has a couple of problems. The first is that >>I anticipate that most people using my function won't care about the >>reason; they'll just want a True or False answer. Their ideal API would >>look like this: >> >>if do_something(): >> # It succeeded >>else: >> # It failed >> >>The second is that the common path is success, which is hidden away in >>the 'else' clause. This seems unintuitive. >> >>2. >> >>Put the method on an object, which stores the reason for a failure: >> >>if obj.do_something(): >> # It succeeded >>else: >> # It failed; obj.get_error_reason() can be called if you want to know >>why >> >>This has an API that is closer to my ideal True/False, but requires me >>to maintain error state inside an object. I'd rather not keep extra >>state around if I don't absolutely have to. >> >>3. >> >>error = do_something() >>if error: >> # It failed >>else: >> # It succeeded >> >>This is nice and simple but suffers from cognitive dissonance in that >>the function returns True (or an object evaluating to True) for >>failure. >> >>4. >> >>The preferred approach works like this: >> >>if do_something(): >> # Succeeded >>else: >> # Failed >> >>BUT this works too... >> >>ok = do_something() >>if ok: >> # Succeeded >>else: >> # ok.reason has extra information >> reason = ok.reason >> >>This can be implemented by returning an object from do_something() that >>has a __nonzero__ method that makes it evaluate to False. This solves >>my problem almost perfectly, but has the disadvantage that it operates >>counter to developer expectations (normally an object that evaluates to >>False is 'empty'). >> >>I know I should probably just pick one of the above and run with it, >>but I thought I'd ask here to see if I've missed a more elegant >>solution. >> >>Thanks, >> >>Simon >> > > I should have thought the simplest spelling of your requirements would be > > try: > do_something() > print "It worked" > except: > # it didn't > > However there are good reasons why this pattern isn't often recommended: > it masks types of exception that you may not have anticipated. > The recipe for only catching known errors but giving them all the same response would be
try: do_something() print "It worked!" except (ThisError, ThatError, TheOtherError): print "It failed!" regards Steve -- Steve Holden +44 150 684 7255 +1 800 494 3119 Holden Web LLC/Ltd http://www.holdenweb.com Skype: holdenweb http://holdenweb.blogspot.com Recent Ramblings http://del.icio.us/steve.holden -- http://mail.python.org/mailman/listinfo/python-list