[Tutor] best practice: throw exception or set a flag?
Steven D'Aprano
steve at pearwood.info
Fri Feb 4 03:11:52 CET 2011
Alex Hall wrote:
> Hi all,
> I am wondering what the best way to do the following would be: throw
> an exception, or always return an object but set an error flag if
> something goes wrong?
Raise an exception. Error flags are an anti-pattern -- a software idiom
that you should not follow.
The problem with flags is that callers will forget to check them, which
leads to problems being revealed far away from where the problem was
caused. That makes it *really* hard to debug.
result = function(x) # fails and sets an error flag in result
do_something_else()
data = [1, 2, 'a', result, 'xyz'] # store
another_function(data)
# ...
# ...
# lots more code here
# ...
# ...
x = data[3]
do_something_with(x)
which then blows up, because x is invalid but you haven't checked the
error flag. The problem actually was with the *original* x, all the way
back at the start, but that's been thrown away now, never to be seen
again, which makes it hard to debug why it failed.
A million, billion, trillion times worse is if you have a single global
error flag! That's *disastrous*, because you MUST check the flag
*immediately*, otherwise it can be cleared.
x = function(100000000) # fails
y = another_function(1000)
if global_error_flag:
# seems to be safe to use x
process(x) # but it isn't, and this blows up
the problem being that another_function makes a second call to
function(), only this one succeeds and resets the global flag. If you do
this, the ghost of a thousand programmers will drag your spirit off to
the nether regions of Hell, where you will have to debug the Windows
kernel using only the `ed` editor on a keyboard missing the letters "x",
"s" and "1" for all of eternity.
For those who don't know the `ed` editor, it is "the standard Unix editor":
http://www.gnu.org/fun/jokes/ed.msg.html
> Which is the "standard" way when dealing with objects? Throw
> exceptions or always return an object, even if said object has an
> error and may therefore not have data beyond an error code and
> message? If I go the exception route, can I somehow put a message into
> the exception, maybe adding it as an attribute of my custom exception
> class? I assume so...
> except e:
> print e.message
Most standard is to raise an exception. The syntax is:
raise ValueError("any message you like")
or use whatever error type suits your problem. You can even define your
own exception types:
class MyError(ValueError):
pass
Less common, but still reasonable, is to raise an error sentinel in
place of the normal result. For example, re.match() and re.search()
return None when there is nothing found, instead of a MatchObject.
Another example, str.find() returns -1.
The disadvantage of this is obvious:
>>> string = "Nobody expects the Portuguese Inquisition!"
>>> offset = string.find("Spanish")
>>> print(string[offset:]) # expecting "Spanish Inquisition!"
!
For special purposes, like mathematics, you can define error values that
propagate through calculations. Python has half-hearted support for
such "Not A Number" codes:
>>> nan = float('nan')
>>> nan + 1 # doesn't fail, but propagates
nan
>>> nan**2
nan
>>> nan - 1000
nan
as well as infinity. But you should consider this a very specialized
solution (as well as a lot of work!!!).
Another non-standard solution is to return a pair of values, a flag plus
the value you actually want:
flag, value = function(10000)
if flag:
do_something_with(value)
else:
process_error()
> or something like that. I know I have research to do about the
> specifics of all this, but before I go off and look it all up I am
> wondering if it is the best way to go as far as standards and best
> coding practices. This is still that api wrapper, so I am not the only
> one who may end up using this file and I want to make it into
> something that is useable and does what people expect. TIA.
Then there is absolutely not even a shadow of a doubt: use exceptions.
--
Steven
More information about the Tutor
mailing list