Python exit commands - why so many and when should each be used? - python

It seems that python supports many different commands to stop script execution.The choices I've found are: quit(), exit(), sys.exit(), os._exit()
Have I missed any?
What's the difference between them? When would you use each?

Let me give some information on them:
quit() simply raises the SystemExit exception.
Furthermore, if you print it, it will give a message:
>>> print (quit)
Use quit() or Ctrl-Z plus Return to exit
>>>
This functionality was included to help people who do not know Python. After all, one of the most likely things a newbie will try to exit Python is typing in quit.
Nevertheless, quit should not be used in production code. This is because it only works if the site module is loaded. Instead, this function should only be used in the interpreter.
exit() is an alias for quit (or vice-versa). They exist together simply to make Python more user-friendly.
Furthermore, it too gives a message when printed:
>>> print (exit)
Use exit() or Ctrl-Z plus Return to exit
>>>
However, like quit, exit is considered bad to use in production code and should be reserved for use in the interpreter. This is because it too relies on the site module.
sys.exit() also raises the SystemExit exception. This means that it is the same as quit and exit in that respect.
Unlike those two however, sys.exit is considered good to use in production code. This is because the sys module will always be there.
os._exit() exits the program without calling cleanup handlers, flushing stdio buffers, etc. Thus, it is not a standard way to exit and should only be used in special cases. The most common of these is in the child process(es) created by os.fork.
Note that, of the four methods given, only this one is unique in what it does.
Summed up, all four methods exit the program. However, the first two are considered bad to use in production code and the last is a non-standard, dirty way that is only used in special scenarios. So, if you want to exit a program normally, go with the third method: sys.exit.
Or, even better in my opinion, you can just do directly what sys.exit does behind the scenes and run:
raise SystemExit
This way, you do not need to import sys first.
However, this choice is simply one on style and is purely up to you.

The functions* quit(), exit(), and sys.exit() function in the same way: they raise the SystemExit exception. So there is no real difference, except that sys.exit() is always available but exit() and quit() are only available if the site module is imported (docs).
The os._exit() function is special, it exits immediately without calling any cleanup functions (it doesn't flush buffers, for example). This is designed for highly specialized use cases... basically, only in the child after an os.fork() call.
Conclusion
Use exit() or quit() in the REPL.
Use sys.exit() in scripts, or raise SystemExit() if you prefer.
Use os._exit() for child processes to exit after a call to os.fork().
All of these can be called without arguments, or you can specify the exit status, e.g., exit(1) or raise SystemExit(1) to exit with status 1. Note that portable programs are limited to exit status codes in the range 0-255, if you raise SystemExit(256) on many systems this will get truncated and your process will actually exit with status 0.
Footnotes
* Actually, quit() and exit() are callable instance objects, but I think it's okay to call them functions.

Different Means of Exiting
os._exit():
Exit the process without calling the cleanup handlers.
exit(0):
a clean exit without any errors / problems.
exit(1):
There was some issue / error / problem and that is why the program is exiting.
sys.exit():
When the system and python shuts down; it means less memory is being used after the program is run.
quit():
Closes the python file.
Summary
Basically they all do the same thing, however, it also depends on what you are doing it for.
I don't think you left anything out and I would recommend getting used to quit() or exit().
You would use sys.exit() and os._exit() mainly if you are using big files or are using python to control terminal.
Otherwise mainly use exit() or quit().

sys.exit is the canonical way to exit.
Internally sys.exit just raises SystemExit. However, calling sys.exitis more idiomatic than raising SystemExit directly.
os.exit is a low-level system call that exits directly without calling any cleanup handlers.
quit and exit exist only to provide an easy way out of the Python prompt. This is for new users or users who accidentally entered the Python prompt, and don't want to know the right syntax. They are likely to try typing exit or quit. While this will not exit the interpreter, it at least issues a message that tells them a way out:
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit
>>> exit()
$
This is essentially just a hack that utilizes the fact that the interpreter prints the __repr__ of any expression that you enter at the prompt.

Related

Python subprocess — how to ignore exit code warnings?

I am trying to display the final results.txt file via default program. I've tried with bare Popen() without run() and got the same effect. The target file is opening (for me it's the see mode) but after exiting it I receive:
Warning: program returned non-zero exit code #256
Is there any way to ignore it and prevent my program from displaying such warning? I don't care about it because it's the last thing the program does, so I don't want people to waste their time clicking Enter each time...
Code's below:
from subprocess import run, Popen
if filepath[len(filepath)-1] != '/':
try:
results = run(Popen(['start', 'results.txt'], shell=True), stdout=None, shell=True, check=False)
except TypeError:
pass
else:
try:
results = run(Popen(['open', 'results.txt']), stdout=None, check=False)
except TypeError:
pass
except FileNotFoundError:
try:
results = run(Popen(['see', 'results.txt']), stdout=None, check=False)
except TypeError:
pass
except FileNotFoundError:
pass
Your immediate error is that you are mixing subprocess.run with subprocess.Popen. The correct syntax is
y = subprocess.Popen(['command', 'argument'])
or
x = subprocess.run(['command', 'argument'])
but you are incorrectly combining them into, effectively
x = subprocess.run(subprocess.Popen(['command', 'argument']), shell=True)
where the shell=True is a separate bug in its own right (though it will weirdly work on Windows).
What happens is that Popen runs successfully, but then you try to run run on the result, which of course is not a valid command at all.
You want to prefer subprocess.run() over subprocess.Popen in this scenario; the latter is for hand-wiring your own low-level functionality in scenarios where run doesn't offer enough flexibility (such as when you require the subprocess to run in parallel with your Python program as an independent process).
Your approach seems vaguely flawed for Unix-like systems; you probably want to run xdg-open if it's available, otherwise the value of os.environ["PAGER"] if it's defined, else fall back to less, else try more. Some ancient systems also have a default pager called pg.
You will definitely want to add check=True to actually make sure your command fails properly if the command cannot be found, which is the diametrical opposite of what you appear to be asking. With this keyword parameter, Python checks whether the command worked, and will raise an exception if not. (In its absence, failures will be silently ignored, in general.) You should never catch every possible exception; instead, trap just the one you really know how to handle.
Okay, I've achieved my goal with a different approach. I didn't need to handle such exception, I did it without the subprocess module.
Question closed, here's the final code (it looks even better):
from os import system
from platform import system as sysname
if sysname() == 'Windows':
system('start results.txt')
elif sysname() == 'Linux':
system('see results.txt')
elif sysname() == 'Darwin':
system('open results.txt')
else:
pass

Code still executes after "quit" or "exit", Python, Spyder

from os.path import join
string=" Congratulations, you are about to embark upon one of life’s "
path=r"C:\Users\Nord.Kind\Desktop"
file="test.txt"
quit()
# This should not execute, but it does!!
with open(join(path,file),"w")as wfile:
wfile.write(string)
wfile.close()
In the above code example the code still executes the write in file command, even though its after a quit.
The same behavious occures when I use exit.
I am using Spyder 3.6
Also the kernel restarts each time I use exit or quit.
Any help?
(Spyder maintainer here) Your question contains this comment:
Also the kernel restarts each time I use exit or quit.
That's the behavior of the IPython kernel we use as a backend to execute users code. Those commands kill the kernel and that forces a kernel restart to maintain its associated console active. I'm afraid there's nothing you can do about it.
Note: The same happens in the Jupyter notebook.
One way is to use sys.exit() in lieu of quit()
import sys
... # code that executes
sys.exit()
... # this code won't execute
However, as noted by #AranFey in the comments, your code will throw an error if it attempts to execute the last part where the variable read is not defined.
You can use SystemExit:
# Code that will run
raise SystemExit
# Code that will not run
sys.exit() also raises this error but this doesn't require importing sys.

quit() works differently in Python-3.x and IPython

The built-in function quit() behaves differently in Python-3.x and IPython 3. The following code prints Hello if executed in IPython, but does not print anything in Python:
quit()
print("Hello")
What is the purpose of quit() in IPython? What was the reason for changing its behavior?
It looks like IPython's quit/exit "function" simplifies to just setting a flag to say "you should exit when this is next checked". It doesn't raise SystemExit itself, so it's presumably dependent on an intermittent check that, if you queue both commands at once, isn't performed until the second command finishes.
You can check it yourself at the IPython prompt, first run quit?? to see that it's a callable class whose __call__ delegates to self._ip.ask_exit(). Next, run quit._ip.ask_exit?? and you'll see that ask_exit just sets a flag, self.exit_now = True (and it's a plain attribute if you check it, not a property with hidden code execution).
You're welcome to track down where IPython is checking that; I'm guessing it's done after any given line or cell of IPython completes.
Fundamentally, the difference is that quit in IPython has never been the same as quit in regular Python's interactive interpeter; quit/exit as a built-in is intended to be replaced for alternate interactive interpreters, and needn't behave exactly the same. If you want a consistent exit behavior, import sys and run sys.exit(), which is also the correct way to exit early inside a script, and is not intended as a hook for the interactive prompt.

Python executables in /usr/bin directory are wrapped in sys.exit

Is there a difference between the two code snippets:
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
main()
Vs
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
I see, most python executables in my ubuntu /usr/bin (or) /usr/local/bin directory use sys.exit. Doesn't the process stop, once the function returns.
Why do people wrap their executable functions inside sys.exit?
Note: This code is taken from openstack-nova python client and this question focusses only on python's sys.exit and not about openstack internals.
sys.exit() is there to pass the right exit code back to shell. If you want to differentiate the response in case of (for example) bad authentication, network issues, broken response, etc. exit codes are useful for that.
If you don't use specific sys.exit(value), you have two options only - success (exit code 0), or exception was thrown (exit code 1).
There are actually two ways to use sys.exit, as explained in the docs.
Your main can return 0 on success and 1 (or any other number from 2-127) on error; that number becomes your program's exit status. (The number 2 has a special meaning; it implies that the failure was because of invalid arguments. Some argument-parsing libraries will automatically sys.exit(2) if they can't parse the command line. The other numbers 3-127 all mean whatever you want them to.)
Or you can return None on success, and a string (or any object with a useful __str__ method) on failure. A None means exit status 0, anything else gets printed to stderr and gives exit status 1.
It used to be traditional to use the second form to signal failure by doing something like return "Failed to open file" from your main function, and the docs still mention doing that, but it's not very common anymore; it's just as easy, and more flexible, to output what you want and return the number you want.
If you just fall off the end of the script without a sys.exit, that's equivalent to sys.exit(0); if you exit through an exception, that's equivalent to passing the traceback to sys.exit—it prints the traceback to stderr and exits with status 1.

What is happening to my process?

I'm executing a SSH process like so:
checkIn()
sshproc = subprocess.Popen([command], shell=True)
exit = os.waitpid(sshproc.pid, 0)[1]
checkOut()
Its important that the process form checkIn() and checkOut() actions before and after these lines of code. I have a test case that involves that I exit the SSH session by closing the terminal window manually. Sure enough, my program doesn't operate correctly and checkOut() is never called in this case. Can someone give me a pointer into what I can look in to fix this bug?
Let me know if any other information would helpful.
Thanks!
The Python process would normally execute in the same window as the ssh subprocess, and therefore be terminated just as abruptly when you close that window -- before getting a chance to execute checkOut. To try and ensure that a function gets called at program exit (though for sufficiently-abrupt terminations, depending on your OS, there may be no guarantees), try Python standard library module atexit.
Perhaps all you need is a try ... finally block?
try:
checkIn()
sshproc = subprocess.Popen([command], shell=True)
exit = os.waitpid(sshproc.pid, 0)[1]
finally:
checkOut()
Unless the system crashes, the process receives SIGKILL, etc., checkOut() should be called.

Categories

Resources