[Python-ideas] Avoiding nested for try..finally: atexit for functions?

Jan Kaliszewski zuo at chopin.edu.pl
Sat Oct 22 02:22:58 CEST 2011


Nikolaus Rath dixit (2011-10-19, 22:19):

> That said, do you have a suggestion for Python 2.7 as well? Maybe
> something like a cleanup error handler?

As Sven noted, the error handler proposed by me is redundant. Such ones
would be redundant too, IMHO.  The appropriate place to catch cleanup
errors would be a cleanup callback itself.

And -- according to another Sven's idea -- callbacks could be registered
together with arguments, e.g.:

    def closing_callback(stream):
        try:
            stream.close()
        except Exception:
            log.critical('Hm, something wrong...', exc_info=True)

    with CleanupMagager() as cm:
        xfile = open(x)
        cm.register(closing_callback, xfile)
        ...

An improved (and at the same time simplified) implementation (being also
a recipe for Python 2.x, though this list is about ideas for Py3.x):

    class CleanupManager(object):

        def __init__(self, initial_callbacks=()):
            self.cleanup_callbacks = list(initial_callbacks)

        def register(self, callback, *args, **kwargs):
            self.cleanup_callbacks.append((callback, args, kwargs))

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc, tb):
            self._next_callback()

        def _next_callback(self):
            if self.cleanup_callbacks:
                callback, args, kwargs = self.cleanup_callbacks.pop()
                try:
                    callback(*args, **kwargs)
                finally:
                    # all cleanup callbacks to be used
                    # Py3.x: all errors to be reported
                    self._next_callback()

I hope it implements well what you explained... I'm not sure if it is
worth to be added to the standard library (in the case of your primary
example I'd rather prefer that try-finally nested structure) -- though
in some cases it may become really useful:

    with CleanupMagager() as cm:
        ...
        cm.register(foo)
        ...
        if cond:
            cm.register(bar)
        else:
            cm.register(spam)
            for x in y:
                cm.register(baz, x)
        ...

Cheers.
*j




More information about the Python-ideas mailing list