On Sun, Aug 27, 2017 at 6:08 AM, Stefan Krah <ste...@bytereef.org> wrote: > On Sat, Aug 26, 2017 at 04:13:24PM -0700, Nathaniel Smith wrote: >> On Sat, Aug 26, 2017 at 7:58 AM, Elvis Pranskevichus <elpr...@gmail.com> >> wrote: >> > What we are talking about here is variable scope leaking up the call >> > stack. I think this is a bad pattern. For decimal context-like uses >> > of the EC you should always use a context manager. For uses like Web >> > request locals, you always have a top function that sets the context >> > vars. >> >> It's perfectly reasonable to have a script where you call >> decimal.setcontext or np.seterr somewhere at the top to set the >> defaults for the rest of the script. > > +100. The only thing that makes sense for decimal is to change localcontext() > to be automatically async-safe while preserving the rest of the semantics.
TBH Nathaniel's argument isn't entirely correct. With the semantics defined in PEP 550 v4, you still can set decimal context on top of your file, in your async functions etc. This will work: decimal.setcontext(ctx) def foo(): # use decimal with context=ctx and this: def foo(): decimal.setcontext(ctx) # use decimal with context=ctx and this: def bar(): # use decimal with context=ctx def foo(): decimal.setcontext(ctx) bar() and this: def bar(): decimal.setcontext(ctx) def foo(): bar() # use decimal with context=ctx and this: decimal.setcontext(ctx) async def foo(): # use decimal with context=ctx and this: async def bar(): # use decimal with context=ctx async def foo(): decimal.setcontext(ctx) await bar() The only thing that will not work, is this (ex1): async def bar(): decimal.setcontext(ctx) async def foo(): await bar() # use decimal with context=ctx The reason why this one example worked in PEP 550 v3 and doesn't work in v4 is that we want to avoid random code breakage if you wrap your coroutine in a task, like here (ex2): async def bar(): decimal.setcontext(ctx) async def foo(): await wait_for(bar(), 1) # use decimal with context=ctx We want (ex1) and (ex2) to work the same way always. That's the only difference in semantics between v3 and v4, and it's the only sane one, because implicit task creation is an extremely subtle detail that most users aren't aware of. We can't have a semantics that let you easily break your code by adding a timeout in one await. Speaking of (ex1), there's an example that didn't work in any PEP 550 version: def bar(): decimal.setcontext(ctx) yield async def foo(): list(bar()) # use decimal with context=ctx In the above code, bar() generator sets some decimal context, and it will not leak outside of it. This semantics is one of PEP 550 goals. The last change just unifies this semantics for coroutines, generators, and asynchronous generators, which is a good thing. Yury _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com