Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #27710 > unrolled thread

Guarding arithmetic

Started byMark Carter <alt.mcarter@gmail.com>
First post2012-08-23 02:05 -0700
Last post2012-08-24 07:48 +1000
Articles 18 — 8 participants

Back to article view | Back to comp.lang.python


Contents

  Guarding arithmetic Mark Carter <alt.mcarter@gmail.com> - 2012-08-23 02:05 -0700
    Re: Guarding arithmetic Chris Angelico <rosuav@gmail.com> - 2012-08-23 19:16 +1000
      Re: Guarding arithmetic Mark Carter <alt.mcarter@gmail.com> - 2012-08-23 02:22 -0700
      Re: Guarding arithmetic Chris Angelico <rosuav@gmail.com> - 2012-08-23 19:29 +1000
      Re: Guarding arithmetic Mark Carter <alt.mcarter@gmail.com> - 2012-08-23 02:22 -0700
    Re: Guarding arithmetic Laszlo Nagy <gandalf@shopzeus.com> - 2012-08-23 11:23 +0200
      Re: Guarding arithmetic Mark Carter <alt.mcarter@gmail.com> - 2012-08-23 02:47 -0700
      Re: Guarding arithmetic Mark Carter <alt.mcarter@gmail.com> - 2012-08-23 02:47 -0700
    Re: Guarding arithmetic Laszlo Nagy <gandalf@shopzeus.com> - 2012-08-23 11:28 +0200
    Re: Guarding arithmetic Chris Angelico <rosuav@gmail.com> - 2012-08-23 19:30 +1000
    Re: Guarding arithmetic Peter Otten <__peter__@web.de> - 2012-08-23 12:11 +0200
      Re: Guarding arithmetic rusi <rustompmody@gmail.com> - 2012-08-23 10:15 -0700
    Re: Guarding arithmetic Laszlo Nagy <gandalf@shopzeus.com> - 2012-08-23 13:01 +0200
    Re: Guarding arithmetic MRAB <python@mrabarnett.plus.com> - 2012-08-23 12:21 +0100
    Re: Guarding arithmetic Peter Otten <__peter__@web.de> - 2012-08-23 13:28 +0200
    Re: Guarding arithmetic Mark Lawrence <breamoreboy@yahoo.co.uk> - 2012-08-23 15:11 +0100
    Re: Guarding arithmetic Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2012-08-23 14:49 -0400
    Re: Guarding arithmetic Chris Angelico <rosuav@gmail.com> - 2012-08-24 07:48 +1000

#27710 — Guarding arithmetic

FromMark Carter <alt.mcarter@gmail.com>
Date2012-08-23 02:05 -0700
SubjectGuarding arithmetic
Message-ID<8b9a5844-66b0-4940-946a-5e626462cdce@googlegroups.com>
Suppose I want to define a function "safe", which returns the argument passed if there is no error, and 42 if there is one. So the setup is something like:

def safe(x):
   # WHAT WOULD DEFINE HERE?

print safe(666) # prints 666
print safe(1/0) # prints 42

I don't see how such a function could be defined. Is it possible?

[toc] | [next] | [standalone]


#27711

FromChris Angelico <rosuav@gmail.com>
Date2012-08-23 19:16 +1000
Message-ID<mailman.3700.1345713371.4697.python-list@python.org>
In reply to#27710
On Thu, Aug 23, 2012 at 7:05 PM, Mark Carter <alt.mcarter@gmail.com> wrote:
> Suppose I want to define a function "safe", which returns the argument passed if there is no error, and 42 if there is one. So the setup is something like:
>
> def safe(x):
>    # WHAT WOULD DEFINE HERE?
>
> print safe(666) # prints 666
> print safe(1/0) # prints 42
>
> I don't see how such a function could be defined. Is it possible?

That can work ONLY if the division of 1/0 doesn't raise an exception.
This is why the concept of NaN exists; I'm not sure if there's a way
to tell Python to return NaN instead of bombing, but it's most likely
only possible with floating point, not integer.

However, there's an easier way.

try:
    print 1/0
except ZeroDivisionError:
    print 42

Catch the exception and do with it what you will.

ChrisA

[toc] | [prev] | [next] | [standalone]


#27713

FromMark Carter <alt.mcarter@gmail.com>
Date2012-08-23 02:22 -0700
Message-ID<mailman.3701.1345713754.4697.python-list@python.org>
In reply to#27711
On Thursday, 23 August 2012 10:16:08 UTC+1, Chris Angelico  wrote:
> On Thu, Aug 23, 2012 at 7:05 PM, Mark Carter <> wrote:
> > Suppose I want to define a function "safe", which returns the argument passed if there is no error, and 42 if there is one. 

> only possible with floating point, not integer.
> 
> try:
>     print 1/0
> except ZeroDivisionError:
>     print 42

OK, so it looks like a solution doesn't exist to the problem as specified. I guess it's something that only a language with macros could accommodate.

[toc] | [prev] | [next] | [standalone]


#27716

FromChris Angelico <rosuav@gmail.com>
Date2012-08-23 19:29 +1000
Message-ID<mailman.3704.1345714163.4697.python-list@python.org>
In reply to#27711
On Thu, Aug 23, 2012 at 7:22 PM, Mark Carter <alt.mcarter@gmail.com> wrote:
> OK, so it looks like a solution doesn't exist to the problem as specified. I guess it's something that only a language with macros could accommodate.

You're asking for a function to prevent the evaluation of its
arguments from throwing an error. That's fundamentally not possible
with a function call. Exception handling is a much more normal way of
handling it; though if you prefer, you could wrap it up in a function
like this:

def safe_div(num,denom):
  try:
    return num/denom
  except ZeroDivisionError:
    return 42

print safe_div(1,0)  # still a poor name though

ChrisA

[toc] | [prev] | [next] | [standalone]


#27717

FromMark Carter <alt.mcarter@gmail.com>
Date2012-08-23 02:22 -0700
Message-ID<b1bd0444-e8ef-4f03-bd69-208e0c550147@googlegroups.com>
In reply to#27711
On Thursday, 23 August 2012 10:16:08 UTC+1, Chris Angelico  wrote:
> On Thu, Aug 23, 2012 at 7:05 PM, Mark Carter <> wrote:
> > Suppose I want to define a function "safe", which returns the argument passed if there is no error, and 42 if there is one. 

> only possible with floating point, not integer.
> 
> try:
>     print 1/0
> except ZeroDivisionError:
>     print 42

OK, so it looks like a solution doesn't exist to the problem as specified. I guess it's something that only a language with macros could accommodate.

[toc] | [prev] | [next] | [standalone]


#27714

FromLaszlo Nagy <gandalf@shopzeus.com>
Date2012-08-23 11:23 +0200
Message-ID<mailman.3702.1345713811.4697.python-list@python.org>
In reply to#27710
On 2012-08-23 11:05, Mark Carter wrote:
> Suppose I want to define a function "safe", which returns the argument passed if there is no error, and 42 if there is one. So the setup is something like:
>
> def safe(x):
>     # WHAT WOULD DEFINE HERE?
>
> print safe(666) # prints 666
> print safe(1/0) # prints 42
>
> I don't see how such a function could be defined. Is it possible?
You are very vague. "There is an error" - but what kind of error? To 
catch all possible exceptions you could do:

def unsafe(x):
     # put your code here...

def safe(x):
     try:
         return unsafe(x)
     except:
         return 42

Generally, it is a bad idea. Exception handlers were invented because 
they give you a way to handle any error in the call chain. When an 
exception occurs, the interpreter will start searching for an 
appropriate exception handler traversing up in the call chain. By 
converting exceptions into return values, you are bypassing this search. 
Then you will have to write conditions instead of exception handlers 
inside ALL methods in the call chain, creating a "manual" search for the 
handler of the exception. In most cases, this will make your code 
difficult, error prone and hard to read.

In some special cases, this can be a good idea to do.

Can you please let us know when and how would you like to use it?

[toc] | [prev] | [next] | [standalone]


#27719

FromMark Carter <alt.mcarter@gmail.com>
Date2012-08-23 02:47 -0700
Message-ID<73b19a13-5c2d-4ee8-b7e3-a9ee3c75ec37@googlegroups.com>
In reply to#27714
On Thursday, 23 August 2012 10:23:20 UTC+1, Laszlo Nagy  wrote:
> On 2012-08-23 11:05, Mark Carter wrote:

> You are very vague. "There is an error" - but what kind of error?

Assume that it doesn't matter.


> In some special cases, this can be a good idea to do.

Those are the cases that I'm interested in.

[toc] | [prev] | [next] | [standalone]


#27720

FromMark Carter <alt.mcarter@gmail.com>
Date2012-08-23 02:47 -0700
Message-ID<mailman.3706.1345715262.4697.python-list@python.org>
In reply to#27714
On Thursday, 23 August 2012 10:23:20 UTC+1, Laszlo Nagy  wrote:
> On 2012-08-23 11:05, Mark Carter wrote:

> You are very vague. "There is an error" - but what kind of error?

Assume that it doesn't matter.


> In some special cases, this can be a good idea to do.

Those are the cases that I'm interested in.

[toc] | [prev] | [next] | [standalone]


#27715

FromLaszlo Nagy <gandalf@shopzeus.com>
Date2012-08-23 11:28 +0200
Message-ID<mailman.3703.1345714142.4697.python-list@python.org>
In reply to#27710
> That can work ONLY if the division of 1/0 doesn't raise an exception.
> This is why the concept of NaN exists; I'm not sure if there's a way
> to tell Python to return NaN instead of bombing, but it's most likely
> only possible with floating point, not integer.
For integers, Python will always raise an exception when you try to 
divide by zero. And integers has nothing to do with NaN. Because NaN is 
meaningful for floating point numbers only. Python can be compiled to 
raise floating point exceptions. (On Python 2, this is a compile time 
option: FPECTL. On Python 3, this can be configured runtime:  
http://docs.python.org/library/fpectl.html )


[toc] | [prev] | [next] | [standalone]


#27718

FromChris Angelico <rosuav@gmail.com>
Date2012-08-23 19:30 +1000
Message-ID<mailman.3705.1345714240.4697.python-list@python.org>
In reply to#27710
On Thu, Aug 23, 2012 at 7:28 PM, Laszlo Nagy <gandalf@shopzeus.com> wrote:
>> That can work ONLY if the division of 1/0 doesn't raise an exception.
>> This is why the concept of NaN exists; I'm not sure if there's a way
>> to tell Python to return NaN instead of bombing, but it's most likely
>> only possible with floating point, not integer.
>
> For integers, Python will always raise an exception when you try to divide
> by zero. And integers has nothing to do with NaN. Because NaN is meaningful
> for floating point numbers only. Python can be compiled to raise floating
> point exceptions. (On Python 2, this is a compile time option: FPECTL. On
> Python 3, this can be configured runtime:
> http://docs.python.org/library/fpectl.html )

Thanks, that's the sort of thing I meant. I'm not familiar enough with
Python's floating point handler to know those details.

ChrisA

[toc] | [prev] | [next] | [standalone]


#27721

FromPeter Otten <__peter__@web.de>
Date2012-08-23 12:11 +0200
Message-ID<mailman.3707.1345716686.4697.python-list@python.org>
In reply to#27710
Mark Carter wrote:

> Suppose I want to define a function "safe", which returns the argument
> passed if there is no error, and 42 if there is one. So the setup is
> something like:
> 
> def safe(x):
>    # WHAT WOULD DEFINE HERE?
> 
> print safe(666) # prints 666
> print safe(1/0) # prints 42
> 
> I don't see how such a function could be defined. Is it possible?

1/0 is evaluated before safe() is called. Therefore safe() has no chance to 
catch the exception. You have to move the evaluation into the safe() 
function:

>>> def safe(deferred, default=42, exception=Exception):
...     try:
...             return deferred()
...     except exception:
...             return default
... 
>>> print safe(lambda: 666)
666
>>> print safe(lambda: 1/0)
42

[toc] | [prev] | [next] | [standalone]


#27748

Fromrusi <rustompmody@gmail.com>
Date2012-08-23 10:15 -0700
Message-ID<e68c7216-5d08-444f-9424-e7f8561f9754@qa3g2000pbc.googlegroups.com>
In reply to#27721
On Aug 23, 3:11 pm, Peter Otten <__pete...@web.de> wrote:
> Mark Carter wrote:
> > Suppose I want to define a function "safe", which returns the argument
> > passed if there is no error, and 42 if there is one. So the setup is
> > something like:
>
> > def safe(x):
> >    # WHAT WOULD DEFINE HERE?
>
> > print safe(666) # prints 666
> > print safe(1/0) # prints 42
>
> > I don't see how such a function could be defined. Is it possible?
>
> 1/0 is evaluated before safe() is called. Therefore safe() has no chance to
> catch the exception. You have to move the evaluation into the safe()
> function:
>
> >>> def safe(deferred, default=42, exception=Exception):
>
> ...     try:
> ...             return deferred()
> ...     except exception:
> ...             return default
> ...>>> print safe(lambda: 666)
> 666
> >>> print safe(lambda: 1/0)
>
> 42

Nice!

Functional programmers know that once you have a lazy language, you
can simulate all control constructs within that framework. eg in
Haskell one could define an 'if-function' as
iffunc (True,  a, b) = a
iffunc (False, a, b) = b
In most other languages such a definition would not work.

What Peter has demonstrated is that for an eager language like python,
a bare-lambda is a lazy-fying construct

[toc] | [prev] | [next] | [standalone]


#27722

FromLaszlo Nagy <gandalf@shopzeus.com>
Date2012-08-23 13:01 +0200
Message-ID<mailman.3708.1345719712.4697.python-list@python.org>
In reply to#27710
>>>> def safe(deferred, default=42, exception=Exception):
> ...     try:
> ...             return deferred()
> ...     except exception:
> ...             return default

What a beautiful solution! I was wondering if the following would be 
possible:


def test(thing, default, *exc_classes):
     try:
         thing()
     except *exc_classes:
         return default


But it is syntactically invalid.

Here is a workaround that is not so beautiful:


def test(thing, default, *exc_classes):
     try:
         thing()
     except Exception, e:
         for cls in exc_classes:
             if isinstance(e,cls):
                 return default
         raise

print test( (lambda: 1/0), -1, ValueError, ZeroDivisionError) # prints -1

[toc] | [prev] | [next] | [standalone]


#27723

FromMRAB <python@mrabarnett.plus.com>
Date2012-08-23 12:21 +0100
Message-ID<mailman.3709.1345720887.4697.python-list@python.org>
In reply to#27710
On 23/08/2012 12:01, Laszlo Nagy wrote:
>
>>>>> def safe(deferred, default=42, exception=Exception):
>> ...     try:
>> ...             return deferred()
>> ...     except exception:
>> ...             return default
>
> What a beautiful solution! I was wondering if the following would be
> possible:
>
>
> def test(thing, default, *exc_classes):
>       try:
>           thing()
>       except *exc_classes:
>           return default
>
>
> But it is syntactically invalid.
>
> Here is a workaround that is not so beautiful:
>
>
> def test(thing, default, *exc_classes):
>       try:
>           thing()
>       except Exception, e:
>           for cls in exc_classes:
>               if isinstance(e,cls):
>                   return default
>           raise
>
> print test( (lambda: 1/0), -1, ValueError, ZeroDivisionError) # prints -1
>
The 'except' clause accepts a tuple of exception classes, so this works:

def test(thing, default, *exc_classes):
     try:
         thing()
     except exc_classes:
         return default

[toc] | [prev] | [next] | [standalone]


#27725

FromPeter Otten <__peter__@web.de>
Date2012-08-23 13:28 +0200
Message-ID<mailman.3710.1345721290.4697.python-list@python.org>
In reply to#27710
Laszlo Nagy wrote:

>>>>> def safe(deferred, default=42, exception=Exception):
>> ...     try:
>> ...             return deferred()
>> ...     except exception:
>> ...             return default
> 
> What a beautiful solution! I was wondering if the following would be
> possible:
> 
> 
> def test(thing, default, *exc_classes):
>      try:
>          thing()
>      except *exc_classes:
>          return default
> 
> 
> But it is syntactically invalid.

The except clause allows a tuple of exceptions:

>>> def safe(deferred, default, *exceptions):
...     try:
...             return deferred()
...     except exceptions:
...             return default
... 
>>> safe(lambda: 1/0, -1, ValueError, ZeroDivisionError)
-1

[toc] | [prev] | [next] | [standalone]


#27734

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2012-08-23 15:11 +0100
Message-ID<mailman.3714.1345730984.4697.python-list@python.org>
In reply to#27710
On 23/08/2012 10:05, Mark Carter wrote:
> Suppose I want to define a function "safe", which returns the argument passed if there is no error, and 42 if there is one. So the setup is something like:
>
> def safe(x):
>     # WHAT WOULD DEFINE HERE?
>
> print safe(666) # prints 666
> print safe(1/0) # prints 42
>
> I don't see how such a function could be defined. Is it possible?
>

Well you've already got lots of answers but I'm not certain about what 
you're trying to achieve.  If you could explicitly state your 
requirements I'm sure that the numerous MVPs (Most Valuable Pythonistas) 
here would come up with The Best Solution ™ to your problem.

-- 
Cheers.

Mark Lawrence.

[toc] | [prev] | [next] | [standalone]


#27758

FromDennis Lee Bieber <wlfraed@ix.netcom.com>
Date2012-08-23 14:49 -0400
Message-ID<mailman.3727.1345747783.4697.python-list@python.org>
In reply to#27710
On Thu, 23 Aug 2012 02:05:50 -0700 (PDT), Mark Carter
<alt.mcarter@gmail.com> declaimed the following in
gmane.comp.python.general:

> print safe(1/0) # prints 42
>

	1/0 is evaluated before safe() is called... and hence will raise an
exception before getting into the function.

	Python does not defer operations that are arguments of a function
call. You can only defer them by wrapping them into a function...

>>> def safe(arg):
... 	try:
... 		return arg()
... 	except:
... 		return 42
... 	
>>> print safe(lambda : 1/0)
42

	Unfortunately, that means you can't just take an arbitrary equation
and wrap it in a call to safe() as you have to make provision for local
names...

>>> def safe(fnc, *args):
... 	try:
... 		return fnc(*args)
... 	except:
... 		return 42
... 
>>> print safe(lambda a, b : a / b, 1, 0)
42
>>> print safe(lambda a, b : a / b, 1, 1)
1
>>> 
>>> a = 1
>>> b = 0
>>> print safe(lambda a, b : a / b, a, b)
42
>>> b = 2
>>> print safe(lambda a, b : a / b, a, b)
0
>>> 

	By the time you wrap the equation with a lambda all, named, terms,
AND supply the named terms after the lambda, you might as well just wrap
the equation in a plain try/except block.

-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
        wlfraed@ix.netcom.com    HTTP://wlfraed.home.netcom.com/

[toc] | [prev] | [next] | [standalone]


#27765

FromChris Angelico <rosuav@gmail.com>
Date2012-08-24 07:48 +1000
Message-ID<mailman.3732.1345758509.4697.python-list@python.org>
In reply to#27710
On Fri, Aug 24, 2012 at 4:49 AM, Dennis Lee Bieber
<wlfraed@ix.netcom.com> wrote:
>         By the time you wrap the equation with a lambda all, named, terms,
> AND supply the named terms after the lambda, you might as well just wrap
> the equation in a plain try/except block.

But closures spare you that hassle.

>>> a=1
>>> b=0
>>> print(safe(lambda: a/b))
42
>>> b=2
>>> print(safe(lambda: a/b))
0.5

(Example done in Python 3 so semantics are a little different)

ChrisA

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web