On 15 October 2017 at 20:45, Paul Moore email@example.com wrote:
On 15 October 2017 at 06:43, Nick Coghlan firstname.lastname@example.org 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 | email@example.com | Brisbane, Australia