Skip to content
Advertisement

Use Python generator’s .send() when generator is wrapped to act as a context manager

Python’s contextlib provides wrappers to turn generators into context managers:

JavaScript

And generators provide the ability to send values into generators that just yielded:

JavaScript

Is there any way to get both behaviors at the same time? I would like to send a value into my context manager so that it can be used while handling __exit__. So something like this:

JavaScript

I’m not sure if this is a good/reasonable idea or not. I feel like it does break some layer of abstraction since I would be assuming that the context manager was implemented as a wrapped generator.

If it is a viable idea, I’m not sure what something should be.

Advertisement

Answer

The generator underlying a @contextmanager is directly accessible via its gen attribute. Since the generator cannot access the context manager, the latter must be stored before the context:

JavaScript

It is important that the generator has exactly the right amount of yield points – @contextmanager ensures that the generator is exhausted after exiting the context.

@contextmanager will .throw raised exceptions in the context, and .send None when done, for which the underlying generator can listen:

JavaScript

In many cases, it is probably easier to implement the context manager as a custom class, though. This avoids complications from using the same channel to send/recv values and pause/resume the context.

JavaScript
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement