[Python-Dev] PEP 343 and __with__

Jason Orendorff jason.orendorff at gmail.com
Mon Oct 3 23:15:26 CEST 2005


Phillip J. Eby writes:
> You didn't offer any reasons why this would be useful and/or good.

It makes it dramatically easier to write Python classes that correctly
support 'with'.  I don't see any simple way to do this under PEP 343;
the only sane thing to do is write a separate @contextmanager
generator, as all of the examples do.

Consider:

    # decimal.py
    class Context:
        ...
        def __enter__(self):
            ???
        def __exit__(self, t, v, tb):
            ???

    DefaultContext = Context(...)

Kindly implement __enter__() and __exit__().  Make sure your
implementation is thread-safe (not easy, even though
decimal.getcontext/.setcontext are thread-safe!).  Also make sure it
supports nested 'with DefaultContext:' blocks (I don't mean lexically
nested, of course; I mean nested at runtime.)

The answer requires thread-local storage and a separate stack of saved
context objects per thread.  It seems a little ridiculous to me.

Whereas:

    class Context:
        ...
        def __with__(self):
            old = decimal.getcontext()
            decimal.setcontext(self)
            try:
                yield
            finally:
                decimal.setcontext(old)

As for the second proposal, I was thinking we'd have one mental model
for context managers (block template generators), rather than two
(generators vs. enter/exit methods).  Enter/exit seemed superfluous,
given the examples in the PEP.

> [T]his multiplies the difficulty of implementing context managers in C.

Nonsense.

    static PyObject *
    lock_with()
    {
        return PyContextManager_FromCFunctions(self, lock_acquire,
lock_release);
    }

There probably ought to be such an API even if my suggestion is in
fact garbage (as, admittedly, still seems the most likely thing).

Cheers,
-j


More information about the Python-Dev mailing list