[Python-Dev] PEP 340 -- concept clarification

Delaney, Timothy C (Timothy) tdelaney at avaya.com
Wed May 4 02:31:18 CEST 2005


Guido van Rossum wrote:

> I'd like the block statement to be defined exclusively in terms of
> __exit__() though.

This does actually suggest something to me (note - just a thought - no
real idea if it's got any merit).

Are there any use cases proposed for the block-statement (excluding the
for-loop) that do *not* involve resource cleanup (i.e. need an
__exit__)?

This could be the distinguishing feature between for-loops and
block-statements:

1. If an iterator declares __exit__, it cannot be used in a for-loop.
   For-loops do not guarantee resource cleanup.

2. If an iterator does not declare __exit__, it cannot be used in a
block-statement.
   Block-statements guarantee resource cleanup.

This gives separation of API (and thus purpose) whilst maintaining the
simplicity of the concept. Unfortunately, generators then become a pain
:( We would need additional syntax to declare that a generator was a
block generator.

OTOH, this may not be such a problem. Any generator that contains a
finally: around a yield automatically gets an __exit__, and any that
doesn't, doesn't. Although that feels *way* too magical to me (esp. in
light of my example below, which *doesn't* use finally). I'd prefer a
separate keyword for block generators. In that case, having finally:
around a yield would be a syntax error in a "normal" generator.

::

    resource locking(lock):
        lock.acquire()
        try:
            yield
        finally:
            lock.release()

    block locking(myLock):
        # Code here executes with myLock held.  The lock is
        # guaranteed to be released when the block is left (even
        # if via return or by an uncaught exception).

To use a (modified) example from another email::

    class TestCase:

        resource assertRaises (self, excClass):
            try:
                yield
            except excClass:
                return
            else:
                if hasattr(excClass, '__name__'): excName =
excClass.__name__
                else: excName = str(excClass)
                raise self.failureException, "%s is not raised" %
excName

    block self.assertRaises(TypeError):
        raise TypeError

Note that this *does* require cleanup, but without using a finally:
clause - the except: and else: are the cleanup code.

Tim Delaney


More information about the Python-Dev mailing list