[Python-ideas] PEP draft: context variables

Nick Coghlan ncoghlan at gmail.com
Mon Oct 16 00:15:41 EDT 2017

On 15 October 2017 at 20:45, Paul Moore <p.f.moore at gmail.com> wrote:

> On 15 October 2017 at 06:43, Nick Coghlan <ncoghlan at gmail.com> wrote:

> >     # Generator form
> >     def _results_gen(data):
> >         for item in data:
> >             with adjusted_context():
> >                 yield calculate_result(item)
> >
> >     results = _results_gen(data)
> >
> > Today, while these two forms look like they *should* be comparable,
> they're
> > not especially close to being semantically equivalent, as there's no
> > mechanism that allows for implicit context reversion at the yield point
> in
> > the generator form.
> I'll have to take your word for this, as I can't think of an actual
> example that follows the pattern of your abstract description, for
> which I can immediately see the difference.

Interestingly, thinking about the problem in terms of exception handling
flow reminded me of the fact that having a generator-iterator yield while
inside a with statement or try/except block is already considered an
anti-pattern in many situations, precisely because it means that any
exceptions that get thrown in (including GeneratorExit) will be intercepted
when that may not be what the author really intended.

Accordingly, the canonical
guaranteed-to-be-consistent-with-the-previous-behaviour iterator ->
generator transformation already involves the use of a temporary variable
to move the yield outside any exception handling constructs and ensure that
the exception handling only covers the code that it was originally written
to cover:

    def _results_gen(data):
        for item in data:
            with adjusted_context():
                result_for_item = calculate_result(item)
            yield result_for_item

    results = _results_gen(data)

The exception handling expectations with coroutines are different, since an
"await cr" expression explicitly indicates that any exceptions "cr" fails
to handle *will* propagate back through to where the await appears, just as
"f()" indicates that unhandled exceptions in "f" will be seen by the
current frame.

And even if as a new API context variables were to be defined in a
yield-tolerant way, a lot of existing context managers still wouldn't be
"yield safe", since they may be manipulating thread local or process global
state, rather than context variables or a particular object instance.


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20171016/b98f6f51/attachment.html>

More information about the Python-ideas mailing list