[Tutor] How to handle exceptions raised inside a function?
Steven D'Aprano
steve at pearwood.info
Tue Nov 30 22:23:43 CET 2010
Richard D. Moores wrote:
> Please take a look at 2 functions I just wrote to calculate the
> harmonic and geometric means of lists of positive numbers:
> <http://tutoree7.pastebin.com/VhUnZcma>.
>
> Both Hlist and Glist must contain only positive numbers, so I really
> need to test for this inside each function. But is there a good way to
> do this? What should the functions return should a non-positive number
> be detected? Is there a conventional Pythonic way to do this?
There are two basic approaches to handling errors in Python:
(1) Don't do any error checking at all. If the input is bad, an
exception will (hopefully!) be raised. Provided you know that bad input
*will* lead to an exception, and not just plausible-looking but
incorrect result, this is often the simplest way.
(2) If you don't trust that a sensible exception will be raised, then do
your own error checking, and raise an exception.
For numeric work, another approach is to return a floating point NAN
("Not A Number"). Unfortunately Python doesn't give any standard way to
specify *which* NAN is returned, but you can return float("nan") to
return one of them.
A fourth approach, rare in Python, is to return some sort of magic value
to indicate an exceptional case. Just about the only example of this I
can think of is string.find(), which returns -1 to indicate "not found".
A fifth approach, common in some other languages, is to return some
arbitrary value, and set an error flag. The caller then has to write
code like this:
result = function(arguments)
if not last_result_error:
# no error occurred
print "result is", result
If you do this, I will *personally* track you down and beat you to death
with a rather large fish.
*wink*
For what it's worth, I have a module of statistics functions (shameless
plug: http://pypi.python.org/pypi/stats and
http://code.google.com/p/pycalcstats -- feedback and bug reports
welcome) that includes the harmonic and geometric mean. My harmonic mean
looks like this:
def harmonic_mean(data):
try:
m = mean(1.0/x for x in data)
except ZeroDivisionError:
return 0.0
if m == 0.0:
return math.copysign(float('inf'), m)
return 1/m
Notice that if the data includes one or more zeroes, the harmonic mean
itself will be zero: limit as x->0 of 1/x -> infinity, and 1/infinity ->
0. If the sum of reciprocals itself cancels to zero, I return the
infinity with the appropriate sign. The only exceptions that could occur
are:
* mean will raise ValueError if the data is empty;
* if an argument is non-numeric, TypeError will occur when I take the
reciprocal of it.
--
Steven
More information about the Tutor
mailing list