pep-567: Add two more subsections to Rejected Ideas (#550)
This commit is contained in:
parent
72662b81ee
commit
722ab66fac
98
pep-0567.rst
98
pep-0567.rst
|
@ -667,6 +667,104 @@ Given the time frame of the Python 3.7 release schedule it was decided
|
||||||
to defer this proposal to Python 3.8.
|
to defer this proposal to Python 3.8.
|
||||||
|
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
|
||||||
Backwards Compatibility
|
Backwards Compatibility
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue