[Python-Dev] On suppress()'s trail blazing (was Re: cpython: Rename contextlib.ignored() to contextlib.ignore())

Xavier Morel python-dev at masklinn.net
Thu Oct 17 20:40:56 CEST 2013


On 2013-10-17, at 18:06 , Barry Warsaw wrote:
> On Oct 18, 2013, at 01:26 AM, Nick Coghlan wrote:
>> By contrast, suppress() and redirect_stdout() are the *first* general
>> purpose context managers added to contextlib since its incarnation in
>> Python 2.5 (although there have been many various domain specific
>> context manager additions elsewhere in the standard library).
> 
> There's a fundamental conceptual shift here that's worth exploring more, and
> which I think was first identified by RDM.
> 
> Until now, context managers were at their heart (at least IMHO) about managing
> "resources".  A general resource might be an open file, or it might be a
> database transaction, or even the current working directory.  Context managers
> (as expressed elegantly by the `with` statement) are used to ensure that a
> resource acquired for some limited operation is - to Python's best ability -
> "released" at the end of that operation, no matter what happens.  E.g. the
> file is closed even if there's a write error, or the current working directory
> is restored to its original location.

I think there's already a significant split between context managers
which handle the lifecycle of a local resource (file, transaction) and
those which purport to locally alter global-ish state (cwd,
decimal.localcontext, logging.captureWarnings, redirect_stdout).

And the latter worries me (much more than the very localized behavior of
suppress) because I don't see any way to implement them safely and
correctly when mixing it with coroutines in today's Python (some of them
aren't even thread-safe), all of that while I expect coroutines will see
significantly more use in the very near future with yield from and
tulip's promotion of coroutine-style async.

> Just look at the implementation to see this shift in perspective.  It doesn't
> use try/finally, it uses try/except.

Transaction CMs will also use try/except:

    @contextmanager
    def transaction():
        resource = open_tnx()
        try:
            yield resource
            resource.commit()
        except:
            resource.rollback()
            raise


More information about the Python-Dev mailing list