On Wed, Jan 17, 2018 at 8:53 PM, Yury Selivanov <yselivanov...@gmail.com> wrote:
> On Wed, Jan 17, 2018 at 2:24 PM, Guido van Rossum <gvanros...@gmail.com> 
> wrote:
>> Perhaps you can update the PEP with a summary of the rejected ideas from
>> this thread?
>
> The Rejected Ideas section of the PEP is now updated with the below:

I've added two more subsections to Rejected Ideas:


Make Context a MutableMapping
-----------------------------

Making the ``Context`` class implement the ``abc.MutableMapping``
interface would mean that it is possible to set and unset variables
using ``Context[var] = value`` and ``del Context[var]`` operations.

This proposal was deferred to Python 3.8+ because of the following:

1. If in Python 3.8 it is decided that generators should support
   context variables (see :pep:`550` and :pep:`568`), then ``Context``
   would be transformed into a chain-map of context variables mappings
   (as every generator would have its own mapping).  That would make
   mutation operations like ``Context.__delitem__`` confusing, as
   they would operate only on the topmost mapping of the chain.

2. Having a single way of mutating the context
   (``ContextVar.set()`` and ``ContextVar.reset()`` methods) makes
   the API more straightforward.

   For example, it would be non-obvious why the below code fragment
   does not work as expected::

     var = ContextVar('var')

     ctx = copy_context()
     ctx[var] = 'value'
     print(ctx[var])  # Prints 'value'

     print(var.get())  # Raises a LookupError

   While the following code would work::

     ctx = copy_context()

     def func():
         ctx[var] = 'value'

         # Contrary to the previous example, this would work
         # because 'func()' is running within 'ctx'.
         print(ctx[var])
         print(var.get())

     ctx.run(func)


Have initial values for ContextVars
-----------------------------------

Nathaniel Smith proposed to have a required ``initial_value``
keyword-only argument for the ``ContextVar`` constructor.

The main argument against this proposal is that for some types
there is simply no sensible "initial value" except ``None``.
E.g. consider a web framework that stores the current HTTP
request object in a context variable.  With the current semantics
it is possible to create a context variable without a default value::

    # Framework:
    current_request: ContextVar[Request] = \
        ContextVar('current_request')


    # Later, while handling an HTTP request:
    request: Request = current_request.get()

    # Work with the 'request' object:
    return request.method

Note that in the above example there is no need to check if
``request`` is ``None``.  It is simply expected that the framework
always sets the ``current_request`` variable, or it is a bug (in
which case ``current_request.get()`` would raise a ``LookupError``).

If, however, we had a required initial value, we would have
to guard against ``None`` values explicitly::

    # Framework:
    current_request: ContextVar[Optional[Request]] = \
        ContextVar('current_request', initial_value=None)


    # Later, while handling an HTTP request:
    request: Optional[Request] = current_request.get()

    # Check if the current request object was set:
    if request is None:
        raise RuntimeError

    # Work with the 'request' object:
    return request.method

Moreover, we can loosely compare context variables to regular
Python variables and to ``threading.local()`` objects.  Both
of them raise errors on failed lookups (``NameError`` and
``AttributeError`` respectively).

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

Reply via email to