2

Consider the following example:

try:
     print "Try this."
     exit(0)
except:
     print "Failed."
     exit(1)

When this simple example is executed, the following is printed to stdout:

Try this.
Failed.

Forgive me if there is an obvious answer or if this has already been asked, but why does exit(0) (which should give me a clean exit) throw an exception?

I tried using a try: except: loop in an actual use-case script, and found that the script would exit(1) even when the try condition says to exit(0).

So I guess exit(0) is throwing a(n hidden?) exception of some sort, but why? It doesn't show the traceback (such as when CTRL + C is used to generate a KeyboardInterrupt exception), and results in unexpected behavior such as in my case when I'm expecting a 0 return and end up with a 1 return.

Is an exception (any exception) the only way to exit a python script?

LegendaryDude
  • 562
  • 8
  • 23

1 Answers1

1

The exception being raised here is SystemExit Exception. Hence, if you try:

try:
     print "Try this."
     exit(0)
except SystemExit:
     pass
except:
     print "Failed."
     exit(1)

Output is:

Try this.

To prevent this, you can call os._exit() to directly exit, without throwing an exception:

import os
try:
     print "Try this."
     os._exit(0)
except SystemExit:
     pass
except:
     print "Failed."
     os._exit(1)

Quoting user2357112:

os._exit skips finally blocks, context manager __exit__s, exit handlers, and other important cleanup, so outside of a few highly specific cases (I believe most of them involve fork), it's not a good idea to use it.

Community
  • 1
  • 1
Vaibhav Bajaj
  • 1,934
  • 16
  • 29
  • `except not SystemExit` doesn't do what you think it does. – user2357112 Aug 05 '16 at 19:28
  • Okay, please help me out. I meant dont test that exception... – Vaibhav Bajaj Aug 05 '16 at 19:29
  • There's no way to specify "all exceptions but this one". The closest you can get is catching all exceptions with `except BaseException as e` and then un-catching the one you don't want with `if isinstance(e, SystemExit): raise` (with no argument to `raise`). – user2357112 Aug 05 '16 at 19:31
  • How about my editted version? – Vaibhav Bajaj Aug 05 '16 at 19:33
  • `os._exit` skips finally blocks, context manager `__exit__`s, exit handlers, and other important cleanup, so outside of a few highly specific cases (I believe most of them involve `fork`), it's not a good idea to use it. Also, your first code snippet still tries to do `except not SystemExit`. – user2357112 Aug 05 '16 at 19:35
  • @user2357112 Sorry, saved now. Regarding the ` _exit()` function, OP said he wanted a method to prevent an exception being raised. I guess I will mention the harms of it in my answer though. – Vaibhav Bajaj Aug 05 '16 at 19:36