
Question:
I was wandering if there was a way to perform an action before the program closes. I am running a program over a long time and I do want to be able to close it and have the data be saved in a text file or something but there is no way of me interfering with the while True
loop I have running, and simply saving the data each loop would be highly ineffective.
So is there a way that I can save data, say a list, when I hit the x
or destroy the program? I have been looking at the atexit module but have had no luck, except when I set the program to finish at a certain point.
def saveFile(list):
print "Saving List"
with open("file.txt", "a") as test_file:
test_file.write(str(list[-1]))
atexit.register(saveFile(list))
That is my whole atexit
part of the code and like I said, it runs fine when I set it to close through the while loop
.
Is this possible, to save something when the application is terminated?
Answer1:Your atexit
usage is wrong. It expects a function and its arguments, but you're just calling your function right away and passing the result to atexit.register()
. Try:
atexit.register(saveFile, list)
Be aware that this uses the list
reference as it exists at the time you call atexit.register()
, so if you assign to list
afterwards, those changes will not be picked up. Modifying the list itself without reassigning should be fine, though.
You could use the handle_exit
context manager from this ActiveState recipe:
<a href="http://code.activestate.com/recipes/577997-handle-exit-context-manager/" rel="nofollow">http://code.activestate.com/recipes/577997-handle-exit-context-manager/</a>
It handles SystemExit
, KeyboardInterrupt
, SIGINT
, and SIGTERM
, with a simple interface:
def cleanup():
print 'do some cleanup here'
def main():
print 'do something'
if __name__ == '__main__':
with handle_exit(cleanup):
main()
There's nothing you can in reaction to a SIGKILL
. It kills your process immediately, without any allowed cleanup.
Catch the SystemExit
exception at the top of your application, then rethrow it.
There are a a couple of approaches to this. As some have commented you could used signal handling ... your <strong>[Ctrl]+[C]</strong> from the terminal where this is running in the foreground is dispatching a <strong><em>SIGHUP</em></strong> signal to your process (from the terminal's drivers).
Another approach would be to use a non-blocking os.read()
on <em>sys.stdin.fileno
</em> such that you're polling your keyboard one during every loop to see if an "exit" keystroke or sequence has been entered.
A similarly non-blocking polling approach can be implemented using the <em>select
</em> module's functionality. I've see that used with the <em>termios
</em> and <em>tty
</em> modules. (Seems inelegant that it needs all those to save, set changes to, and restore the terminal settings, and I've also seen some examples using <em>os
</em> and <em>fcntl
</em>; and I'm not sure when or why one would prefer one over the other if os.isatty(sys.stdin.fileno())
).
Yet another approach would be to use the <strong>curses
</strong> module with window.nodelay()
or window.timeout()
to set your desired input behavior and then either window.getch()
or window.getkey()
to poll for any input.