[Python-Dev] Proposal: standard way of defining and executing "atexit" functions...

Peter Funk pf@artcom-gmbh.de
Tue, 20 Jun 2000 09:32:33 +0200 (MEST)


Hi Skip, Hi David,

David Ascher:
> > If someone fails to use the defined protocol, screw 'em... ;-)
> 
> That's unreasonable given that existing tools might include a library which
> might be upgraded to use the new mechanism while the old code used its own
> mechanism happily.  For example, I've used my own protocols in the past
> which went something like...
> 
> def register_exitfunc(func):
>     old_exitfunc = getattr(sys, 'exitfunc', None)
>     def wrapper(old_exitfunc=old_exitfunc, new_func=func):
>       if old_exitfunc is not None: old_exitfunc()
>       new_func()
>     sys.exitfunc = wrapper
> 
> or some such, creating a call chain instead of a sequence of calls, and it's
> a 'fine' protocol in that it worked fine in the absence of a standard.  No
> need to break code if we can avoid it.

Davids wrapper function implements a FIFO strategy for termination.  
I think this is not desired.  Normally you want LIFO, because higher level 
services in an application are initialized later during startup.  Those 
services usually depend on lower level services, which should still be 
available at termination time of the higher level services.  

I try to explain this by an example:
Module A provides some kind of network connections. 
Module B uses (imports) Module A to access a remote resource administration 
server to provide access to remote devices or resources.
During program termination Module B likes to release all resources reserved 
for (owned by) the program.  It uses Module A to submit a cleanup request to
the server.  Module A however wants to close all open network connections.

The following function (termination protocol) solves this by exchanging the 
sequence of calls within the wrapper:

def register_exit_func(func, *args, **kw):
    import sys
    previous_func = sys.exit_func
    def wrapped_func(previous_func=previous_func, func=func, args=args, kw=kw):
        try:
            apply(func, args, kw)
        finally:
            if previous_func is not None: 
                previous_func()
    sys.exit_func = wrapped_func

In the past I've placed such a function into a common base module of my apps.
But I think, Skip is right, that a termination protocol should be part of
the standard library.  

But a separate module 'exit.py' seems to be overkill for single basic 
function.  May be it should be put into the module 'os'?  Handling of 
program termination is something, which considered as a generic 
operating system service.  From the users point of view 'sys' would
be a better place, but this would require rewriting in C: ugly.

I also agree with Skip, that the possibility to unregister an exit_func is 
normally not needed.  The same effect can be achieved by doing nothing in 
the exit_func.

Regards, Peter
-- 
Peter Funk, Oldenburger Str.86, D-27777 Ganderkesee, Germany, Fax:+49 4222950260
office: +49 421 20419-0 (ArtCom GmbH, Grazer Str.8, D-28359 Bremen)