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. 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