Re: [Python-Dev] Example for PEP 343

2005-05-18 Thread Nick Coghlan
Guido van Rossum wrote:
 Anyway, perhaps we should provide this most general template:
 
   @do_template
   def with_decimal_context():
   oldctx = decimal.getcontext()
   newctx = oldctx.copy()
   decimal.setcontext(newctx)
   yield newctx
   decimal.setcontext(oldctx)
 
 To be used like this:
 
   do with_decimal_context() as ctx:
   ctx.prec += 2
   # change other settings
   # algorithm goes here


For the 'with' keyword, and the appropriate __enter__/__exit__ methods on 
decimal Contexts, this can be written:

   with decimal.getcontext() as ctx:
   ctx.prec += 2
   # change other settings
   # algorithm goes here
   # Pre-with context guaranteed to be restored here

The decimal.Context methods to make this work:

   def __enter__(self):
   current = getcontext()
   if current is self:
   self._saved_context = self.copy()
   else:
   self._saved_context = current
   setcontext(self)

   def __exit___(self, *exc_info):
   if self._saved_context is None:
   raise RuntimeError(No context saved)
   try:
   setcontext(self._saved_context)
   finally:
   self._saved_context = None

Cheers,
Nick.

-- 
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---
 http://boredomandlaziness.blogspot.com
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Example for PEP 343

2005-05-18 Thread Michael Chermside
Phillip writes:
 @do_template
 def with_extra_precision(places=2):
  Performs nested computation with extra digits of precision.
  decimal.getcontext().prec += 2
  yield None
  decimal.getcontext().prec -= 2

 Won't this do the wrong thing if something within the block alters
 the precision?

Depends on what behavior you want. I wrote it this way partly because
that's how the example in the manual was written, and partly because
I was thinking if someone increased the precision by 3 within the
block, then we probably want to leave it increased by 3 on block
exit.

On careful re-consideration, I think it'd be better to require that
the block NOT make unbalanced changes to the precision... we
could verify it using an assert statement.

I avoided caching the context and restoring it, because I WANTED to
allow code in the block to make OTHER alterations to the context and
not clobber them after the block exits (eg: setting or clearing some
trap). It's debatable whether that was a good design choice... there's
a great deal of elegence to Guido's version used like this:

Guido:
   do with_decimal_context() as ctx:
   ctx.prec += 2
   # change other settings
   # algorithm goes here

However, all of these are minor details compared to the bug that
Raymond points out:

Raymond:
 The final return +s should be unindented.  It should
 be at the same level as the do with_extra_precision().  The purpose of
 the +s is to force the result to be rounded back to the *original*
 precision.

In effect, the with_extra_precision wrapper causes the calculations
to be done with higher precision, AND causes any variables set during
the block will retain their higher precision. (It's because context
controls OPERATIONS but changing context never affects individual
Decimal OBJECTS.) So I fear that the whole with_extra_precision()
idea is just likely to tempt people into introducing subtle bugs, and
it should probably be scrapped anyhow. Guido's approach to save-and-
restore context works fine.

-- Michael Chermside

(PS: Another reason that I avoided a basic save-and-restore is that we
have plenty of examples already of 'do' statements that save-and-restore,
I was trying to do something different. It's interesting that what I
tried may have turned out to be a poor idea.)

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Example for PEP 343

2005-05-17 Thread Michael Chermside
In PEP 343 Guido writes:
8. Another use for this feature is the Decimal context.  It's left
   as an exercise for the reader.  (Mail it to me if you'd like to
   see it here.)

Here are two such examples. Pick your favorite for the PEP.

PS: Writing this helped convince me that allowing the use of generators
instead of classes with the do_template decorator is quite nice in
practice, even though it gets confusing (for beginners anyhow) if you
start to think about it too much.

-- Michael Chermside

# = SAMPLE #1: increasing precision during a sub-calculation =

import decimal

@do_template
def with_extra_precision(places=2):
Performs nested computation with extra digits of precision.
decimal.getcontext().prec += 2
yield None
decimal.getcontext().prec -= 2



# == SAMPLE USE of #1 ==
# (Sample taken from the Python Library Reference)

def sin(x):
Return the sine of x as measured in radians.
do with_extra_precision():
i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
while s != lasts:
lasts = s
i += 2
fact *= i * (i-1)
num *= x * x
sign *= -1
s += num / fact * sign
return +s

# = SAMPLE #2: insisting on exact calculations only =

import decimal

@do_template
def assert_exact():
Raises exception if nested computation is not exact.
ctx = decimal.getcontext()
was_inexact = ctx.traps[decimal.Inexact]
ctx.traps[decimal.Inexact] = True
yield None
ctx.traps[decimal.Inexact] = was_inexact


# == SAMPLE USE of #2 ==

# Lemma 2 ensures us that each fraction will divide evenly
do assert_exact():
total = decimal.Decimal(0)
for n, d in zip(numerators, denominators):
total += n / d

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Example for PEP 343

2005-05-17 Thread Raymond Hettinger


 -Original Message-
 From: [EMAIL PROTECTED] [mailto:python-dev-
 [EMAIL PROTECTED] On Behalf Of Phillip J. Eby
 Sent: Tuesday, May 17, 2005 6:06 PM
 To: Michael Chermside; [EMAIL PROTECTED]
 Cc: python-dev@python.org
 Subject: Re: [Python-Dev] Example for PEP 343
 
 At 02:42 PM 5/17/2005 -0700, Michael Chermside wrote:
 
 # = SAMPLE #1: increasing precision during a sub-calculation
=
 
 import decimal
 
 @do_template
 def with_extra_precision(places=2):
  Performs nested computation with extra digits of precision.
  decimal.getcontext().prec += 2
  yield None
  decimal.getcontext().prec -= 2
 
 Won't this do the wrong thing if something within the block alters the
 precision?

Right.

It should save, alter, and then restore:

   oldprec = decimal.getcontext().prec
   decimal.getcontext().prec += 2
   yield None
   decimal.getcontext().prec = oldprec


Raymond Hettinger
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Example for PEP 343

2005-05-17 Thread Guido van Rossum
What's the advantage of using two calls to getcontext() vs. saving the
context in a local variable?

On 5/17/05, Raymond Hettinger [EMAIL PROTECTED] wrote:
 
 
  -Original Message-
  From: [EMAIL PROTECTED] [mailto:python-dev-
  [EMAIL PROTECTED] On Behalf Of Phillip J. Eby
  Sent: Tuesday, May 17, 2005 6:06 PM
  To: Michael Chermside; [EMAIL PROTECTED]
  Cc: python-dev@python.org
  Subject: Re: [Python-Dev] Example for PEP 343
 
  At 02:42 PM 5/17/2005 -0700, Michael Chermside wrote:
 
  # = SAMPLE #1: increasing precision during a sub-calculation
 =
  
  import decimal
  
  @do_template
  def with_extra_precision(places=2):
   Performs nested computation with extra digits of precision.
   decimal.getcontext().prec += 2
   yield None
   decimal.getcontext().prec -= 2
 
  Won't this do the wrong thing if something within the block alters the
  precision?
 
 Right.
 
 It should save, alter, and then restore:
 
oldprec = decimal.getcontext().prec
decimal.getcontext().prec += 2
yield None
decimal.getcontext().prec = oldprec
 
 
 Raymond Hettinger
 ___
 Python-Dev mailing list
 Python-Dev@python.org
 http://mail.python.org/mailman/listinfo/python-dev
 Unsubscribe: 
 http://mail.python.org/mailman/options/python-dev/guido%40python.org
 


-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Example for PEP 343

2005-05-17 Thread Raymond Hettinger
 What's the advantage of using two calls to getcontext() vs. saving the
 context in a local variable?

I prefer saving the context in a local variable but that is just a
micro-optimization.  The presentation with multiple calls to
getcontext() was kept just to match the style of the original -- the
important change was the absolute save and restore versus the original
relative adjust up and adjust down.


Raymond
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Example for PEP 343

2005-05-17 Thread Raymond Hettinger
  What's the advantage of using two calls to getcontext() vs. saving
the
  context in a local variable?
 
 I also prefer saving the context in a local variable but that is just
a
 micro-optimization.  The presentation with multiple calls to
 getcontext() was kept just to match the style of the original -- the
 important change was the absolute save and restore versus the original
 relative adjust up and adjust down.

One more thought:  Rather than just saving the precision, it is likely
wiser, safer, and more general to just save and restore the whole
context and let the wrapped block only work with a copy.

oldcontext = decimal.getcontext()
newcontext = oldcontext.copy()
newcontext.prec += 2
yield None
decimal.setcontext(oldcontext)

This approach defends against various kinds of unruly behavior by the
yield target.



Raymond Hettinger
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Example for PEP 343

2005-05-17 Thread Raymond Hettinger
 I think you're missing a decimal.setcontext(newcontext) before the
 yield..

Right.
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Example for PEP 343

2005-05-17 Thread Guido van Rossum
On 5/17/05, Raymond Hettinger [EMAIL PROTECTED] wrote:
  I think you're missing a decimal.setcontext(newcontext) before the
  yield..
 
 Right.

I don't see a call to setcontext() in the sin() example in the library
reference. Is that document wrong? I thought that simply modifying the
parameters of the current context would be sufficient.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Example for PEP 343

2005-05-17 Thread Bob Ippolito

On May 17, 2005, at 10:36 PM, Guido van Rossum wrote:

 On 5/17/05, Raymond Hettinger [EMAIL PROTECTED] wrote:

 I think you're missing a decimal.setcontext(newcontext) before the
 yield..


 Right.


 I don't see a call to setcontext() in the sin() example in the library
 reference. Is that document wrong? I thought that simply modifying the
 parameters of the current context would be sufficient.

The library reference isn't modifying the parameters in a *copy* of  
the current context.

-bob

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Example for PEP 343

2005-05-17 Thread Guido van Rossum
[Raymond Hettinger]
 The sin() example is correct.  The precision is changed and restored in
 the current context.

I got that eventually. :-)

 However, for a general purpose wrapper, it is preferable to make a
 context copy and then restore the context after the enclosed is run.
 That guards against the enclosed block making any unexpected context
 changes.

(Although if people get in the habit of using the provided wrappers
and the do-statement, there won't be any unexpected changes.)

 Also, since the wrapper is intended to work like a try/finally, it will
 make sure the context gets restored even if an exception is raised at
 some unexpected point in the middle of the computation.

Yes, that's the point of the do-statement. :-

Anyway, perhaps we should provide this most general template:

  @do_template
  def with_decimal_context():
  oldctx = decimal.getcontext()
  newctx = oldctx.copy()
  decimal.setcontext(newctx)
  yield newctx
  decimal.setcontext(oldctx)

To be used like this:

  do with_decimal_context() as ctx:
  ctx.prec += 2
  # change other settings
  # algorithm goes here

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Example for PEP 343

2005-05-17 Thread Bob Ippolito

On May 17, 2005, at 11:39 PM, Guido van Rossum wrote:

 [Raymond Hettinger]

 However, for a general purpose wrapper, it is preferable to make a
 context copy and then restore the context after the enclosed is run.
 That guards against the enclosed block making any unexpected context
 changes.


 (Although if people get in the habit of using the provided wrappers
 and the do-statement, there won't be any unexpected changes.)


 Also, since the wrapper is intended to work like a try/finally, it  
 will
 make sure the context gets restored even if an exception is raised at
 some unexpected point in the middle of the computation.


 Yes, that's the point of the do-statement. :-

 Anyway, perhaps we should provide this most general template:

   @do_template
   def with_decimal_context():
   oldctx = decimal.getcontext()
   newctx = oldctx.copy()
   decimal.setcontext(newctx)
   yield newctx
   decimal.setcontext(oldctx)

 To be used like this:

   do with_decimal_context() as ctx:
   ctx.prec += 2
   # change other settings
   # algorithm goes here

I have yet to use the decimal module much, so I may be completely off  
here.. but why not write it like this:

@do_template
def with_decimal_context():
 curctx = decimal.getcontext()
 oldctx = curctx.copy()
 yield curctx
 decimal.setcontext(oldctx)

Saves a line and a context set :)

-bob

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com