Alan Gauld wrote: > On 20/03/15 09:37, Peter Otten wrote: > >>> def close_relay(e=None,v=None,t=None): >>> try: >>> if not relay_closed() >>> really_close_relay() >>> except: >>> really_close_relay() > > The purpose of the if clause is to ensure that > if the function is called many times you only > close the relay once (I surmised that more than > once could be harmful?) > >>> import sys, atexit >>> atexit.register(close_relay) >>> sys.excepthook = close_relay > > atexit should be overkill, but it might be needed > if for some reason the interpreter dies while > performing the usual cleanup. > > excepthook replaces the usual exception mechanism > with a clean up. This is needed for cases where an > exception occurs before getting to the finally. We > want to close the relay ASAP, not waiting till > the interpreter decides to call the finally. > >>> try: >>> main program here >>> finally: >>> close_relay() > > This is the happy path where everything shuts down as expected. > >> That reeks of cargo cult. Are there actual scenarios for each of the >> three mechanisms where it is the only one that works? > > In real-time you never trust anything. > Always cover your back. > >> I would expect that >> >> try: >> main program here >> finally: >> close_relay() >> >> provides the same level of confidence, > > Only if the interpreter is behaving as normal. > The hooks are to try (we hope) to catch cases where > the interpreter has broken its normal flow. > > So the scenarios are: > > 1) an unexpected exception occurs - close the relay ASAP. > - Use excepthook > > 2) The interpreter gets sent a kill or similar unexpected > termination - use atexit because finally may not get > called. (I'm not sure, so belt n' braces here) > (BTW Does anyone know what the interpreter does when > suspending - Ctrl-Z in Unix land?) > > 3) Normal program exit. Use the finally clause. > > But its only ever going to be a best endeavour, that's > why Python is not suitable for true real-time/critical apps... > But I'd never trust any environment to its usual behaviour > if there is a possibility of something being broken. > In this case the relay and its battery pack. > >> the program closes normally or the main code raises an exception, but not >> if the process is killed. > > What's not clear in the Python documentation is how Python responds > to a kill(or suspend). I'd hope the atexit got called even in a kill. > I would not expect the finally to be executed. > > Of course, if its a seg fault you are probably stuffed either way...
I ran a few experiments: $ cat bnb.py import atexit import os import signal import sys import time def handle_except(*args): print("except", args, flush=True) def handle_exit(): print("exit", flush=True) def register_signalhandler(sig): def handler(*args): print("receiving signal", sig, args, flush=True) signal.signal(sig, handler) def main(): print("Hello from", os.getpid()) while True: print(".", flush=True, end="") time.sleep(1) sys.excepthook = handle_except atexit.register(handle_exit) for sig in sys.argv[1:]: register_signalhandler(getattr(signal, sig)) try: main() finally: print("finally", flush=True) $ python3 bnb.py Hello from 32578 ....^Cfinally except (<class 'KeyboardInterrupt'>, KeyboardInterrupt(), <traceback object at 0x7ff97b001bc8>) exit When there is no signal handler all three mechanisms work, in the order - finally - except hook - exit handler Now let's kill: $ python3 bnb.py Hello from 32584 .............Terminated None of the three are invoked. Let's install a signal handler for SIGTERM: $ python3 bnb.py SIGTERM Hello from 32593 .................receiving signal 15 (15, <frame object at 0x7f818e0bb648>) ...............^Cfinally except (<class 'KeyboardInterrupt'>, KeyboardInterrupt(), <traceback object at 0x7f818cdc6bc8>) exit The signal is intercepted (and ignored by the no-op handler thus the additional Ctrl-C). If we raise a SystemExit in the handler - finally - exit handler will be invoked, but not the except hook. $ kill -9 of course cannot be intercepted. My conclusions: - If finally does not work nothing does. - Signal handlers increase safety Bonus: $ python3 bnb.py SIGTSTP Hello from 32614 ........^Zreceiving signal 20 (20, <frame object at 0x7f2f8a897648>) ........^Cfinally except (<class 'KeyboardInterrupt'>, KeyboardInterrupt(), <traceback object at 0x7f2f895a2bc8>) exit So Ctrl-Z can be intercepted. The program could put the relay into a safe state before it suspends. _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor