Message348878
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? |
|
Date |
User |
Action |
Args |
2019-08-01 23:33:04 | Antony.Lee | set | recipients:
+ Antony.Lee |
2019-08-01 23:33:04 | Antony.Lee | set | messageid: <1564702384.75.0.948740630584.issue37743@roundup.psfhosted.org> |
2019-08-01 23:33:04 | Antony.Lee | link | issue37743 messages |
2019-08-01 23:33:04 | Antony.Lee | create | |
|