Pythonic API design: detailed errors when you usually don't care

Simon Willison swillison at
Mon Oct 2 18:45:38 CEST 2006

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:


except HttpError:
  # An HTTP error occurred
except ApplicationError:
  # An application error occurred
  # 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
  # It failed

The second is that the common path is success, which is hidden away in
the 'else' clause. This seems unintuitive.


Put the method on an object, which stores the reason for a failure:

if obj.do_something():
  # It succeeded
  # It failed; obj.get_error_reason() can be called if you want to know

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.


error = do_something()
if error:
  # It failed
  # 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


The preferred approach works like this:

if do_something():
  # Succeeded
  # Failed

BUT this works too...

ok = do_something()
if ok:
  # Succeeded
  # 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



More information about the Python-list mailing list