Run Code after Your Program Exits with Python’s AtExit
Register cleanup functions that run after your script ends or errors
In this article I’ll show you how to register functions that execute when your program exits with python’s built-in module atexit. This means that you can run code after your code exits (due to an error of when it’s finished), providing you with all kinds of essential tools to execute clean-up functions, save your data, and make debugging easier. Let’s code!
1. Understanding atexit with simple examples
The main concept is to register a function that gets executed when the script exits. This can happen for many reasons which we’ll get into later. Let’s start with the simplest example and gradually make it more useful.
Simplest example — registering a function
The code below demonstrates most basic way of registering a exit-function.
In the code above we simply register the say_goodbye
function and then call the simple_example
function. When the script ends after simple_example()
has completed you’ll see that say_goodbye
executes. This is also visible in the output:calling the function..
Function enter
Function exit
exiting now, goodbye
Easy! Let’s make it a little more complex.
Simple example — exiting a loop
We adjust the simple_example
function a little: it now contains an infinite loop that prints “still running..” every second. Again we register the say_goodbye
function, only now at the start of the simple_example
function.
Now when we run the code we’ll see a “still running..” message each second. When we exit by pressing ctrl-c we see the following output:still running..
still running..
still running..
still running..
still running..
exiting now, goodbye
So before we entered the infinite loop, we registered the say_goodbye
function. This function will execute when the interpreter terminates.
2. Simpler and multiple registrations
In the previous part we’ve seen that its pretty important where you place the atexit.register
bit of code. If we register the function after the while loop the function will never get registered.
In this part we explore a new way of registering the functions so that you don’t have to worry about this problem. Also we discover that you can register multiple multiple functions
we can exit all we want It is possible to have multiple functions registered atexit. Also, registration can be a bit simpler.
Simpler registration with a decorator
By registering functions with a decorator you don’t have to worry about when you register the function since they happen as soon as the interpreter reaches your function definition. They are also super easy to use:
Another advantage is that your code is much cleaner; the simpel_example()
function is not ‘polluted’ with the atexit registration. Check out this article if you want to learn more about how decorator work and how to create your own.
Registering multiple functions
It is easy to register multiple functions to execute at exit. The important thing is to remember they are executed in the reversed order in which they were registered. Check out the code below:
You can see the order by the outputs below:still running..
still running..
# 1 says au revoir
# 2 says later
# 3 says goodbye
Unregistering a function
This is as easy as registering a function:
The code above will produce the following output (notice that “# 2” doesn’t show):Function enter
Function exit
# 1
You can also clear all registered functions using atexit._clear()
.
Registering a function with arguments
The code below allows you to pass arguments to the registered exit-function. This can be pretty useful for passing data to your registration function that you don’t know beforehand:
The code above produces the following output:what is your name? mike
Function enter
Function exit
-mike says hoi after 0:00:01.755111
-mike says hello after 0:00:01.755111
-mike says bonjour after 0:00:01.755111
-mike says gutentag after 0:00:01.755111
Manually trigger all registered exit functions
The code below demonstrates how to manually trigger all registered exit-functions with the atexit._run_exitfuncs()
function:
The output looks like this:start
exiting now, au revoir
exiting now, later
exiting now, goodbye
continue with code
When does atexit run the registered functions?
Good question. Exit function get executed upon normal interpreter termination. This means that they run when your script ends normally, when sys.exit(0)
quit()
or raising an exception like raise ValueError("oops")
.
Abnormal termination is a situation in which the program is killed by a signal that is not handled by Python or when a Python fatal internal error is detected. The last case is when os._exit(0)
is called; this exits without calling cleanup handlers, flushing stdio buffers, etc. As an example:
will produce:start
exiting now, goodbye
Wheereas replacing sys.exit(0)
by os._exit(0)
will not run the say_goodbye
function.
Conclusion
In this article we’ve explored the inner workings of Python’s atexit function, and how and when to use it.
I hope this article was as clear as I hope it to be but if this is not the case please let me know what I can do to clarify further. In the meantime, check out my other articles on all kinds of programming-related topics like these:
- Git for absolute beginners: understanding Git with the help of a video game
- Create and publish your own Python package
- A complete guide to using environment variables and files with Docker and Compose
Happy coding!
— Mike
P.S: like what I’m doing? Follow me!