The Many Ways to Exit in Python

2021-10-10 Show me the exit

It’s fundamentally useful to exit your program when it’s done. Here are five(!) ways to do so in Python.

1. raise SystemExit()

We can exit from Python code by raising a SystemExit exception:

print("Done.")
raise SystemExit()

The top level interpreter catches this special exception class and triggers its exit routine. This includes such steps as running all atexit functions, deleting all objects, and finally calling the OS exit function.

SystemExit optionally takes an integer for the exit code, where 0 represents success and any other value represents failure. We can use this to signal calling programs that an error occurred:

print("Woops.")
raise SystemExit(1)

(When Python crashes with an exception, it uses an exit code of 1.)

If you’re looking for a quick answer, you can stop reading here. Use raise SystemExit(<code>) as the obviousest way to exit from Python code and carry on with your life.

...

More obscurely, we can pass SystemExit any object, in which case Python will print the str() of that object to stderr and return an exit code of 1:

raise SystemExit("Woops.")

This can be handy, but I’d argue being explicit is clearer:

print("Woops.", file=sys.stderr)
raise SystemExit(1)

2. sys.exit()

We can also call sys.exit() to exit Python, optionally with an exit code:

import sys

sys.exit(1)

Underneath this only does raise SystemExit(<arg>) (in C).

Whilst sys.exit() is a little less typing than raise SystemExit(), it does require the import, which is a bit inconvenient. Also it hides the detail that an exception is raised.

3. exit() and quit()

exit() and quit() are “extra builtins” added by Python’s site module. Both essentially call raise SystemExit(), optionally with an exit code, like:

exit(1)

This looks super convenient! We don’t need to import anything, and the names are very short.

Unfortunately, the site module is optional. We can be skip loading it by running Python with the -S flag. In which case our call to quit() or exit() can still exit, but with a NameError exception:

$ python -S -c 'exit(1)'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
NameError: name 'exit' is not defined

Because exit() and quit() are optional, I’d recommend avoiding using them in your programs. But they’re fine to use at the REPL, which is why they exist. They even print usage information when written without brackets, to help new users trying to exit the REPL:

>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit

That message leads us to...

4. Ctrl-D (from the REPL)

Ctrl-D is the universal keyboard shortcut for exit. It sends EOF (End of File) to the current program, telling it the user is done sending input and it should exit.

Ctrl-D works with every command line program, including python. So it’s best to learn this shortcut, rather than use the Python-specific exit(). Then you can exit bash, zsh, ipython, sqlite, and any other command line program, without giving it a second thought.

5. os._exit()

The os._exit(n) function exits Python immediately with the given exit code n. It does so by calling the underlying OS exit function directly.

Unlike raising SystemExit, using os._exit() prevents Python from running its normal exit process. This is very destructive and usually undesirable, hence the “private/danger” underscore prefx.

The only reason I’ve found for calling os._exit() is when debugging in cases where raising SystemExit doesn’t work. For example, in a thread, raising SystemExit does not exit the progarm - it only stops the thread. Directly calling os._exit() can stop the entire program, which can be combined with a few well-placed debug prints to inspect state.

So, it’s worth knowing that os._exit() exists, although you should avoid it in day-to-day life.

✨Bonus✨ 6. Directly calling the OS exit function

os._exit() is a thin wrapper around our OS’ underlying exit function. We can call this function directly through Python’s ctypes module. This doesn’t confer any advantage - in fact it’s worse, because our code won’t work on all OS’s. But it’s cool to know about.

On Linux/macOS/other Unixes, the exit function is available in the C standard library as exit(). We see its details by running man 3 exit - the Linux man page is online here. We can call it with ctypes like so:

from ctypes import CDLL
from ctypes.util import find_library


libc = CDLL(find_library("libc"))
libc.exit(1)

Pretty neat!

Fin

Thanks to Anthony Sottile for the tip to use raise SystemExit(...) in this video.

I hope you have found the exit you’re looking for,

—Adam


📙👉Speed Up Your Django Tests👈📙


Subscribe via RSS, Twitter, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: python