Can "quit" be made to quit?

Experts like you have no need for this. The goal is to make Python more beginner friendly.

When a user does type quit, it is unreasonable for the REPL not to quit as it does in IPython. For us, it just a matter of figuring out the cleanest way to implement it.

5 Likes

I think it’s worth noting that typing quit at a sqlite3 prompt simply does this:

sqlite> quit
   ...> 

Remembering the . seems analogous to me to remembering the (). Making quit do something without parentheses seems to be a bad lesson for beginners, to me; it would create an expectation that python functions with things that look more like shell commands, rather than functions and expressions.

6 Likes

Agree here, quit() showcases the reliability and consistency of python for the beginners.

5 Likes

The problem here seems to boil down to the fact that quit or exit are meta-commands, if you will, that act not within the interpreter but on the interpreter. In that light, having them be “magic” like %quit isn’t so far fetched.

That also separates it from sys.exit() which is clearly a within-the-interpreter command to gracefully exit the program.

I find it somewhat frustrating that we periodically spend so much time and effort arguing about this, when there are no fewer than four trivially easy ways to exit the Python REPL:

  • quit() and exit()

  • Ctrl-D or Ctrl-Z ENTER

  • Just close the terminal window or tab

and yet we cannot get any traction on providing even one simple way to clear the REPL. But I digress.

How far can a beginner get in Python without learning that

  1. functions must be called with brackets (parentheses); and

  2. the function name alone always refers to the object itself, it does not call the function?

This is not a rhetorical question. Surely this is something that people have to learn in the first twenty minutes of using Python.

Why is it “unreasonable” to call the quit function with parens, but not everything else? If it is unreasonable for quit to need parens, then it is also unreasonable for help, and random, and len and all the other functions.

IPython allows paren-free function calls too. As do other languages like Ruby. Of course, paren-less function calls cause its own issues.

If “IPython does it” is the gold standard for good UI, then the obvious question is why not just use IPython? Or if that is unacceptable, for some reason, does that mean that we ought to duplicate IPython’s magics? For example, if the Python REPL is a shell, and is expected to behave like a shell, then it must be “unacceptable” to need two lines and parentheses (and quotation marks!) to change the working directory:

import os

os.chwd('some/location')

IPython allows cd some/location just like it allows quit to quit.

Again, not a rhetorical question: how far do we go? IPython is an amazingly rich and powerful shell. How far towards duplicating the functionality of their magics system should we go? To me, it doesn’t seem reasonable to spend time and effort to specially handle only exit and quit as magic shell commands when there are so many other useful commands we could have.

Commands which are not just useful for beginners, but could be useful for experienced developers as well.

If we’re going to do this, and complicate the Python reference implementation with a new concept of “magical commands which have an immediate effect in the REPL” (as opposed to ordinary functions which need to be called with parens) then let’s not unnecessarily and artifically limit it to the trivial and boring quit/exit.

1 Like

I don’t agree that your distinction between “meta-commands” and commands is meaningful. quit and exit don’t directly call sys.exit but they raise SystemExit, which is precisely what sys.exit does. All of them exit the interpreter.

(As does EOF, i.e. Ctrl-D on posix systems, and Ctrl-Z ENTER on Windows.)

So your meta-commands and your ordinary command sys.exit fundamentally do the same thing: they exit the interpreter.

(To be pedantic, quit and exit do some extra work in order to defeat IDLE, which catches and ignores SystemExit. But then IDLE also pops up a dialog box asking if you really want to exit, which is even more annoying than having to type the parentheses. But I digress.)

There is another way in which your distinction fails: by default, under normal circumstances, both exit and quit are available to the non-interactive interpreter too:


[steve ~]$ python3.10 -c "print(quit, exit, sep=' --- ')"

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

So we are free to use those functions in ordinary scripts:


[steve ~]$ cat exit_test.py 

print("starting...")

quit("and now exiting")  # or use exit

# The following is dead code.

while True:

    pass



[steve ~]$ python3.10 exit_test.py 

starting...

and now exiting

[steve ~]$ echo $?

1

Hypothetically, we might choose to introduce a distintion between existing functions (to be pedantic: “callables”) like quit and exit, and a new class of entities “commands” which only exist in the interactive REPL, like IPython magics. But that distinction doesn’t currently exist.

I feel that one driver for this thread is the frustration that quit prints a “pedantic” message, like “nah, I understood what you meant, but I’m in a capricious mood, I demand that you re-type this with parentheses”. As silly as it may sound, maybe it will give this impression less to beginners if it’s rephrased to make it clear that not using parentheses is a mistake, like

>>> quit
<built-in function quit (if you meant to exit the interpreter, use "quit()")

Right now, the user may not understand why Python doesn’t do what they want if it perfectly understood it. This would emphasize that this is just a guess.

12 Likes

if these bells and whistles are going to be added then at the least add a command-line option to have it behave in the traditional way, like python --no-magic or just python -n. those that want the traditional way without typing a -n will need to learn enough to make a script that does it.

Should that also disable other REPL-specific features like the way expressions get printed out automatically and captured into the variable named _ ? You know, to make sure people don’t get confused.

the option should revert it back to the way it was prior to whatever PEP makes this change (etc). no previous features to be lost.

Apart from “this is what I’m used to right now, please don’t change anything” (which is an argument, though not a particularly strong one), what justification have you for this no-magic option? If you don’t want magic, surely you don’t want ANY magic, and you want the REPL to behave exactly like running a script?

I don’t think that distinction is as clear as you say. If we wanted exit and quit to only be available in the interactive interpreter, we could have easily made them conditional on the existence of sys.ps1, say. But we didn’t. It is true that if you run the interpreter after disabling site.py with -S, you lose access to them, but you also lose access to other features which are used in scripts, like site-specific packages.

I don’t believe that Python currently makes a firm distinction between “commands to the interpreter” and “part of the language”. For example, exit and sys.exit do more or less the same thing; why is one an interpreter command and the other part of the language? Both are available in scripts; both are available interactively. Both are just regular objects that ultimately work by raising SystemExit, which is part of the language.

If you are serious about taking quit and exit “away from the language” and making them unavailable to scripts by default, that would be a breaking change and would have to go through the usual deprecation period.

i might like to try out the new magic. i might even find it useful. but i would imagine some people want the plain old REPL. i’m just suggesting to do that, albeit via an option. someone might even argue for the reverse sense (--magic), but not i. i’m just thinking that the way it is intend to be used should be the no option way. typing in an option is not that hard. coding to see and set the flag to disable all the new shell-ish command features might be harder. i assume this is for an interactive shell. scripts would just be all-natural python.

i already have lots of scripts written in python i use in my interactive shells. i still have a few bash scripts that use some python assistance. a python interactive that is as easy as bash would be an interesting thing.

Trying to get this thread back on track, or closed, this is what it takes to add auto-quitting as safe as I could make it:

diff --git a/Lib/site.py b/Lib/site.py
index 7faf1c6f6a..ff3e9ad7ef 100644
--- a/Lib/site.py
+++ b/Lib/site.py
@@ -401,6 +401,18 @@ def setquit():
     builtins.exit = _sitebuiltins.Quitter('exit', eof)
 
 
+def enableautoquit():
+    """Enable typing 'quit' to exit interpreter"""
+    original_displayhook = sys.displayhook
+
+    def displayhook(value):
+        if isinstance(value, _sitebuiltins.Quitter):
+            value()
+        return original_displayhook(value)
+
+    sys.displayhook = displayhook
+
+
 def setcopyright():
     """Set 'copyright' and 'credits' in builtins"""
     builtins.copyright = _sitebuiltins._Printer("copyright", sys.copyright)
@@ -597,6 +609,8 @@ def main():
     known_paths = addusersitepackages(known_paths)
     known_paths = addsitepackages(known_paths)
     setquit()
+    if not sys.flags.isolated:
+        enableautoquit()
     setcopyright()
     sethelper()
     if not sys.flags.isolated:

What do core devs think of this?

2 Likes

That already exists, as has been discussed at some length in this thread.

1 Like

As mentioned before, I think we need an orthogonal way to express REPL commands at the prompt, one which cannot be mistaken for Python code. The same goes for the other hacks such as “copyright”, “credits” or “license”.

My preference would be slash commands as these are pretty common in today’s interactive chat world and would be quite normal for newbies to use.

1 Like

I think the reasonable solution is to provide the freedom to customize the shell for users. For example, if sys.interpreterhook(tokens) were provided, the new function will be called when enter key is pressed in the shell but before pushing to the interpreter so that the user can customize the real command to pass.

Actually, I have coded and used it in my customized shell. For example, please see the example code and the demonstration here.

It would be completely unnecessary for beginners, but for seniors, the sky’s the limit. (I’m positive about the word :slightly_smiling_face:)

Adding special REPL commands needs UX research and has implications on the REPL of all implementations, which makes it PEP-sized in my opinion.

In the short term, interested people can take my snippet of code for their usercustomize.
It does not help beginners of course, who will still have to learn that exit/quit are normal functions that need parens, or that all consoles can be exited with Ctrl-D (or platform equivalent).

(Personally I find the repr message helpful, not snarky. But I don’t see the same message as Jean Abou Samra!)

You might be surprised if you saw some of the questions I close on Stack Overflow on a daily basis.

The argument isn’t that it’s unreasonable to need parens to call the quit function; the argument is that it’s unreasonable to need to call a function in order to quit the interpreter. After all, you didn’t write Python code to start the interpreter, either. If we are going to reinforce the understanding that the interpreter is a separate program that sits outside of the code being typed in, and interprets pieces of it one at a time (as opposed to how a script works), it stands to reason that this same program should accept other interactions, too. random and len are operating on existing Python objects; quit conceptually is operating on the interpreter. (help is a less clear-cut case; it can be envisioned either way.)

I think the proposal is predicated upon forming this distinction, yes.

I am, consequent to the above, serious about it, and I understand that it takes time to deprecate things that way. (Better, IMO, than being super-strict about semver and blowing up the version number to 100+ like web browsers do nowadays - since it doesn’t work anyway.)

That said, several alternate proposals ITT also make sense - including the “just change the string to be more regular and less presumptive” one.