[Python-Dev] Merging PEP 310 and PEP 340-redux?

Shane Hathaway shane at hathawaymix.org
Fri May 13 03:51:26 CEST 2005


Guido van Rossum wrote:
> Going for all-out simplicity, I would like to be able to write these examples:
> 
> class locking:
>     def __init__(self, lock): self.lock = lock
>     def __enter__(self): self.lock.acquire()
>     def __exit__(self, *args): self.lock.release()
> 
> class opening:
>     def __init__(self, filename): self.filename = filename
>     def __enter__(self): self.f = open(self.filename); return self.f
>     def __exit__(self, *args): self.f.close()\
> 
> And do EXPR as VAR: BLOCK would mentally be translated into
> 
> itr = EXPR
> VAR = itr.__enter__()
> try: BLOCK
> finally: itr.__exit__(*sys.exc_info()) # Except sys.exc_info() isn't
> defined by finally

If it's this simple, it should be possible to write something that
combines the acquisition of multiple resources in a single statement.
For example:

    with combining(opening(src_fn), opening(dst_fn, 'w')) as src, dst:
        copy(src, dst)

I think the following class would do it.

    class combining:
        def __init__(self, *resources):
            self.resources = resources
            self.entered = 0

        def __enter__(self):
            results = []
            try:
                for r in self.resources:
                    results.append(r.__enter__())
                    self.entered += 1
                return results
            except:
                # exit resources before re-raising the exception
                self.__exit__()
                raise

        def __exit__(self, *args):
            last_exc = None
            # exit only the resources successfully entered
            to_exit = self.resources[:self.entered]
            while to_exit:
                r = to_exit.pop()
                try:
                    r.__exit__(*args)
                except:
                    # re-raise the exception after exiting the others
                    last_exc = sys.exc_info()
            if last_exc is not None:
                raise last_exc[0], last_exc[1], last_exc[2]

Would that work?

Shane


More information about the Python-Dev mailing list