New submission from Antony Lee <[email protected]>:
The docs for ContextDecorator (of which contextmanager is a case) describe its
semantics as:
... for any construct of the following form:
def f():
with cm():
# Do stuff
ContextDecorator lets you instead write:
@cm()
def f():
# Do stuff
However, when decorating a generator, the equivalence is broken:
from contextlib import contextmanager
@contextmanager
def cm():
print("start")
yield
print("stop")
def gen_using_with():
with cm():
yield from map(print, range(2))
@cm()
def gen_using_decorator():
yield from map(print, range(2))
print("using with")
list(gen_using_with())
print("==========")
print("using decorator")
list(gen_using_decorator())
results in
using with
start
0
1
stop
==========
using decorator
start
stop
0
1
i.e., when used as a decorator, the entire contextmanager is executed first
before iterating over the generator (which is unsurprising given the
implementation of ContextDecorator: ContextDecorator returns a function that
executes the context manager and returns the generator, which is only iterated
over later).
Should this be considered as a bug in ContextDecorator, and should
ContextDecorator instead detect when it is used to decorate a generator (e.g.
with inspect.isgeneratorfunction), and switch its implementation accordingly in
that case?
----------
components: Library (Lib)
messages: 348878
nosy: Antony.Lee
priority: normal
severity: normal
status: open
title: How should contextmanager/ContextDecorator work with generators?
versions: Python 3.8
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue37743>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com