Hi Christoph,
Adding context manager protocol support to contextvars.Token was
considered when PEP 567 was discussed. There wasn't a strong argument
against that; however we decided not to immediately add it because
context variables is a relatively low-level API. In you case, you can
simply wrap a ContextVar in a context manager:
_setting = contextvars.ContextVar('setting')
@contextlib.contextmanager
def setting(value):
tok = _setting.set(value)
try:
yield
finally:
_setting.reset(tok)
and later:
with setting(something): ...
Yury
On Wed, Jun 5, 2019 at 11:19 AM Christoph Groth
<[email protected]> wrote:
>
> It seems that the following idea has not been raised here before. If it
> has been, I'd be grateful for a pointer to the relevant discussion.
>
> The idea is: how about adding context manager interface (__enter__ and
> __exit__ methods) to the contextvars.Token type?
>
> This would allow code like this:
>
> with var.set(1):
> # var.get() == 1
>
> that would be equivalent to the following more verbose snippet (taken
> from PEP 567):
>
> token = var.set(1)
> try:
> # var.get() == 1
> finally:
> var.reset(token)
>
> I attach a very rough proof-of-concept implementation of the idea. The
> proper way to implement this proposal would be of course to modify the
> _contextvars C-extension.
>
> Here is my motivation for this proposal:
>
> The contextvars module is promoted as a replacement for thread-local
> storage for asynchronous programming, but in fact it seems to me that
> ContextVars implement thread-safe and async-safe dynamic scoping [1] in
> Python.
>
> One of the uses of dynamic scoping is as an alternative to function
> parameters for library configuration [2]. While dynamic scoping by
> default (as in Emacs Lisp) can be dangerous, I believe that explicit
> dynamic scoping could be useful in the Python world as a means to avoid
> the "parameter hell" of some libraries, perhaps most infamously
> demonstrated by matplotlib. With the updated ContextVars, a
> hypothetical plotting library could be used like this:
>
> with plotting.line_thickness.set(2), plotting.line_style('dashed'):
> plotting.plot(x, y)
>
> As explained in [2], the advantages of this approach compared to
> argument passing is that other functions that internally use
> plotting.plot do not have to expose all of its configuration options by
> themselves as parameters. Also, with the same mechanism it is possible
> to set a parameter for a single invocation of plotting.plot, or a
> default value for a whole script.
>
> [1]
> https://en.wikipedia.org/wiki/Scope_(computer_science)#Dynamic_scoping
> [2] https://www.gnu.org/software/emacs/emacs-paper.html#SEC18
>
> _______________________________________________
> Python-ideas mailing list -- [email protected]
> To unsubscribe send an email to [email protected]
> %(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s
> Code of Conduct: http://python.org/psf/codeofconduct/
--
Yury
Python-Ideas mailing list -- python-dev(a)python.org
To unsubscribe send an email to python-ideas-leave(a)python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/