Re: [Tutor] How to handle exceptions raised inside a function?

2010-12-01 Thread Steven D'Aprano

Patty wrote:
This is very interesting to me - the below excerpt is something I was 
trying to do for one of my programs and gave up on it:


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*


I think I was trying to do something like thius at the end of a function 
I wrote-


return 2  or return my_special_integer_mvar


That syntax won't work. However, the basic idea is (moderately) sound: 
your function has a special value that means something funny happened. 
Python very occasionally uses this:


 hello world.find(z)  # not found
-1

which you then use like this:

result = string.find(target)
if result == -1:  # special value
print(not found)
else:
print(found at position %d % result)

In general, this idiom is mildly disparaged in Python circles, but not 
forbidden. Exceptions are usually considered better.


However, what I'm talking about is quite different. Here's how I might 
write the string find method using this (horrible) implementation:



# Global status flag.
find_succeeded = 0

def find(string, target):
global find_succeeded
if target in string:
find_succeeded = 1
return string.find(target)
else:
find_succeeded = 0
# I never know what number to return...
return 42  # that'll do...

(In low-level languages like C, the number returned on failure (where I 
choose 42) is often whatever value happens to be in some piece of memory 
-- essentially a random number.)



result = find(hello world, z)
if find_succeeded == 1:
print(found at position %d % result)
else:
print(not found)


This is even more inconvenient and difficult than earlier. Consider what 
happens if you want to do two or more searches. Because they all report 
their status via the one global variable, you must inspect the global 
after each call, before making the next call, or the status will be 
lost. In Python you can do this:


results = [s.find(target) for s in list_of_strings]

and then, later, inspect each individual result to see if it was -1 or 
not. But with the global status idiom, you can't do that, because the 
status flag is lost once you call find() again.




--
Steven

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How to handle exceptions raised inside a function?

2010-12-01 Thread patty
I think I understand, I will have to reread this a couple times!  But I do
consider myself a C programmer so that probably explains why I was trying
to write code that way.  And you are right 'you must inspect the global
 after each call, before making the next call'.  I *was* setting up the
function to check on and muck with this mvar before the end where I
'return' my own thing.

So for Python programming you are advising us to use one of the other 
four approaches to error handling and not try to do something like:

call custom function, something is returned to a mvar while processing
each statement, which is then examined for content and if one of three
'bad' or 'good' things are in the mvar, trying to avoid return values of
[0 1 -1 2 -2] because off-the-top-of-my-head these are meaningful in
various languages, so come up with 3 way-out-there-numbers-of-my-own, such
as your '42'example.  Then try and 'return' this from the function back to
the calling function, possibly main().  Then examine return value integer
and have ' if statements' doing something depending...

So does this mean I am thinking through this like a C programmer?

And I don't think I would be checking a variable at all using the other
four ways, I would just let an error happen and let the return value be
whatever it is and let the exception come up (or my custom exception
handler) and handle it, instead I was trying to get right in the middle of
it and force things.  Also I was trying to use the return value for
purposes other than error.  I think what I was trying to do would be like
a Case Statement
really if that were supported in Python.


 return my_special_integer_mvar

So the above will not work?  If you were to try this, do you have to
return digits?  You can't return an mvar (and hope it doesn't change on
you while going back to calling program)?

Thanks for confirming my understanding or confusion as the case may be!!

Patty


 Patty wrote:
 This is very interesting to me - the below excerpt is something I was
 trying to do for one of my programs and gave up on it:

 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*

 I think I was trying to do something like thius at the end of a function
 I wrote-

 return 2  or return my_special_integer_mvar

 That syntax won't work. However, the basic idea is (moderately) sound:
 your function has a special value that means something funny happened.
 Python very occasionally uses this:

   hello world.find(z)  # not found
 -1

 which you then use like this:

 result = string.find(target)
 if result == -1:  # special value
  print(not found)
 else:
  print(found at position %d % result)

 In general, this idiom is mildly disparaged in Python circles, but not
 forbidden. Exceptions are usually considered better.

 However, what I'm talking about is quite different. Here's how I might
 write the string find method using this (horrible) implementation:


 # Global status flag.
 find_succeeded = 0

 def find(string, target):
  global find_succeeded
  if target in string:
  find_succeeded = 1
  return string.find(target)
  else:
  find_succeeded = 0
  # I never know what number to return...
  return 42  # that'll do...

 (In low-level languages like C, the number returned on failure (where I
 choose 42) is often whatever value happens to be in some piece of memory
 -- essentially a random number.)


 result = find(hello world, z)
 if find_succeeded == 1:
  print(found at position %d % result)
 else:
  print(not found)


 This is even more inconvenient and difficult than earlier. Consider what
 happens if you want to do two or more searches. Because they all report
 their status via the one global variable, you must inspect the global
 after each call, before making the next call, or the status will be
 lost. In Python you can do this:

 results = [s.find(target) for s in list_of_strings]

 and then, later, inspect each individual result to see if it was -1 or
 not. But with the global status idiom, you can't do that, because the
 status flag is lost once you call find() again.



 --
 Steven

 ___
 Tutor maillist  -  Tutor@python.org
 To unsubscribe or change subscription options:
 http://mail.python.org/mailman/listinfo/tutor




___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How to handle exceptions raised inside a function?

2010-12-01 Thread Richard D. Moores
On Tue, Nov 30, 2010 at 13:23, Steven D'Aprano st...@pearwood.info wrote:
 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?


 (2) If you don't trust that a sensible exception will be raised, then do
 your own error checking, and raise an exception.

I'll go with this one because I do want both Hlist and Glist to
contain only positive real numbers. So I'll go with Jerry Hill's
suggestion for both H and G. See the two revised functions at
http://tutoree7.pastebin.com/VfYLpFQq.

 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)

An impressive collection. Thanks for sharing!

 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

math.copysign! Didn't know about that one. But mean? It's not a
built-in function..

Dick

 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.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How to handle exceptions raised inside a function?

2010-12-01 Thread Steven D'Aprano

Richard D. Moores wrote:
[...]

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


math.copysign! Didn't know about that one. But mean? It's not a
built-in function..


No, it's not, it's a function from my stats module.

The naive version is simple:

def mean(data):
return sum(data)/len(data)


My version is a bit more complicated than that, in order to minimize 
round-off error and support iterators.




--
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How to handle exceptions raised inside a function?

2010-12-01 Thread Richard D. Moores
On Tue, Nov 30, 2010 at 13:23, Steven D'Aprano st...@pearwood.info wrote:

 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)

Your readme says:
Installation


stats requires Python 3.1. To install, do the usual:

python3 setup.py install

I'm afraid I've never fully understood instructions like that. I have
Python 3.1. I now have your stats-0.1.1a. where do I put it to do the
above? It's now in 3.1's site-packages. Do I CD to stats-0.1.1a and
run that command? Or?

Could I have put stats-0.1.1a anywhere, CD-ed to that anywhere, and
then run the command?

I hesitate to experiment because I don't want your files sprayed all
over my hard disk.

Thanks,

Dick
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How to handle exceptions raised inside a function?

2010-12-01 Thread James Mills
On Thu, Dec 2, 2010 at 10:27 AM, Richard D. Moores rdmoo...@gmail.com wrote:
 Could I have put stats-0.1.1a anywhere, CD-ed to that anywhere, and
 then run the command?

Yes.

python setup.py install essentially instructs
distutils (or setuptools or distribute - whichever is being used)
to install the package into your site-packages or
$PYTHONPATH (if configured that way by means of configuration).

NB: Copying the package's directory into site-packages hwoever
has the same effect. The directory that contains the __init__.py

cheers
James


-- 
-- James Mills
--
-- Problems are solved by method
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How to handle exceptions raised inside a function?

2010-12-01 Thread Richard D. Moores
On Wed, Dec 1, 2010 at 16:41, James Mills prolo...@shortcircuit.net.au wrote:
 On Thu, Dec 2, 2010 at 10:27 AM, Richard D. Moores rdmoo...@gmail.com wrote:
 Could I have put stats-0.1.1a anywhere, CD-ed to that anywhere, and
 then run the command?

 Yes.

Thanks, James. Did that.

Thought I'd publicize Steven's stuff a bit. I pasted the help on
module stats at http://tutoree7.pastebin.com/bhcjhRuV

Dick
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How to handle exceptions raised inside a function?

2010-11-30 Thread Jerry Hill
On Tue, Nov 30, 2010 at 3:00 PM, Richard D. Moores rdmoo...@gmail.com wrote:
 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?

If the value passed to the function is illegal, you should raise a
ValueError exception.  Something like this in your harmonic_mean
function, maybe:

if not all(x  0 for x in Hlist):
raise ValueError(All items in Hlist must be positive numbers.)

-- 
Jerry
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How to handle exceptions raised inside a function?

2010-11-30 Thread Steven D'Aprano

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
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] How to handle exceptions raised inside a function?

2010-11-30 Thread Patty
This is very interesting to me - the below excerpt is something I was trying 
to do for one of my programs and gave up on it:


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*


I think I was trying to do something like thius at the end of a function I 
wrote-


return 2  or return my_special_integer_mvar

and then do something or other depending on this value once it passes back 
to calling function or main().  I think I used similar code as you have 
above.  It didn't go well and also there seemed to be a problem related to 
where I was returning this value _to_ (where I actually placed this snippet 
of code like you wrote above) -  a function or module I wrote or main().


So, could you expand on this for me?  I would have to dig around to find the 
actual program I was working on.


Thanks,

Patty



- Original Message - 
From: Steven D'Aprano st...@pearwood.info

To: tutor@python.org
Sent: Tuesday, November 30, 2010 1:23 PM
Subject: Re: [Tutor] How to handle exceptions raised inside a function?



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
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor




___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor