Fun with with

Klaas mike.klaas at gmail.com
Fri Dec 1 18:53:56 EST 2006


Occasionally I find myself wanting a block that I can break out of at
arbitrary depth--like java's named break statements.  Exceptions can
obviously be used for this, but it doesn't always look nice.

The with statement can be used to whip up something quite usable:

class ExitBlock(object):
    """ A context manager that can be broken out of at an arbitrary
depth,
    using .exit() """
    def __init__(self):
        class UniqueException(BaseException):
            pass
        self.breakExc = UniqueException
    def exit(self):
        raise self.breakExc()
    def __enter__(self):
        return self
    def __exit__(self, t, v, tb):
        return t is self.breakExc

Now the most important thing here is that each exit block creates a
unique exception type.  If you have philosophical issues with creates
unboundedly many type objects, you can use unique instances too.

This allows named break-out-able blocks:

        with ExitBlock() as ex1:
            with ExitBlock() as ex2:
                with ExitBlock() as ex3:
                    while True:
                        ex2.exit()
                print 'not displayed'
            print 'execution proceeds here from ex2.exit()'
            while True:
                for x in xrange(sys.maxint):
                    while True:
                        ex1.exit()
            print 'not displayed'
        print 'execution proceeds here from ex1.exit()'

The only danger is bare except (or except BaseException) inside the
block.

-Mike




More information about the Python-list mailing list