On Wed, Aug 30, 2017 at 8:55 AM, Greg Ewing
Yury Selivanov wrote:
BTW we already have mechanisms to always propagate context to the caller -- just use threading.local() or a global variable.
But then you don't have a way to *not* propagate the context change when you don't want to.
Here's my suggestion: Make an explicit distinction between creating a new binding for a context var and updating an existing one.
So instead of two API calls there would be three:
contextvar.new(value) # Creates a new binding only # visible to this frame and # its callees
contextvar.set(value) # Updates existing binding in # context inherited from caller
contextvar.get() # Retrieves the current binding
If we assume an extension to the decimal module so that decimal.localcontext is a context var, we can now do this:
async def foo(): # Establish a new context for this task decimal.localcontext.new(decimal.Context()) # Delegate changing the context await bar() # Do some calculations yield 17 * math.pi + 42
async def bar(): # Change context for caller decimal.localcontext.prec = 5
Interesting. Question: how to write a context manager with contextvar.new? var = new_context_var() class CM: def __enter__(self): var.new(42) with CM(): print(var.get() or 'None') My understanding that the above code will print "None", because "var.new()" makes 42 visible only to callees of __enter__. But if I use "set()" in "CM.__enter__", presumably, it will traverse the stack of LCs to the very bottom and set "var=42" in in it. Right? If so, how can fix the example in PEP 550 Rationale: https://www.python.org/dev/peps/pep-0550/#rationale where we zip() the "fractions()" generator? With current PEP 550 semantics that's trivial: https://www.python.org/dev/peps/pep-0550/#generators Yury