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?

-----Original Message----- From: python-dev-bounces+python=rcn.com@python.org [mailto:python-dev- bounces+python=rcn.com@python.org] On Behalf Of Phillip J. Eby Sent: Tuesday, May 17, 2005 6:06 PM To: Michael Chermside; gvanrossum@gmail.com 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

What's the advantage of using two calls to getcontext() vs. saving the context in a local variable? On 5/17/05, Raymond Hettinger <python@rcn.com> wrote:
-----Original Message----- From: python-dev-bounces+python=rcn.com@python.org [mailto:python-dev- bounces+python=rcn.com@python.org] On Behalf Of Phillip J. Eby Sent: Tuesday, May 17, 2005 6:06 PM To: Michael Chermside; gvanrossum@gmail.com 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/)

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

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

On May 17, 2005, at 9:02 PM, Raymond Hettinger wrote:
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.
I think you're missing a decimal.setcontext(newcontext) before the yield.. -bob

On 5/17/05, Raymond Hettinger <python@rcn.com> 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/)

On May 17, 2005, at 10:36 PM, Guido van Rossum wrote:
On 5/17/05, Raymond Hettinger <python@rcn.com> 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

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 sin() example is correct. The precision is changed and restored in the current context. 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. 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. Raymond

[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/)

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

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 | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.blogspot.com
participants (5)
-
Bob Ippolito
-
Guido van Rossum
-
Nick Coghlan
-
Phillip J. Eby
-
Raymond Hettinger