There are multiple separate problems with this code:
while run:
# loop through each line of user input, adding it to buffer
for line in sys.stdin.readlines():
if line == 'quit':
run = False
First, you have an inner loop that won't finish until all lines have been processed, even if you type "quit" at some point. Setting run = False
doesn't break out of that loop. Instead of quitting as soon as you type "quit", it will keep going until it's looked at all of the lines, and then quit if you typed "quit" at any point.
You can fix this one pretty easily by adding a break
after the run = False
.
But, with or without that fix, if you didn't type "quit" during that first time through the outer loop, since you've already read all input, there's nothing else to read, so you'll just keep running an empty inner loop over and over forever that you can never exit.
You have a loop that means "read and process all the input". You want to do that exactly once. So, what should the outer loop be? It should not be anyway; the way to do something once is to not use a loop. So, to fix this one, get rid of run
and the while run:
loop; just use the inner loop.
Then, if you type "quit", line
will actually be "quit\n"
, because readlines
does not strip newlines.
You fix this one by either testing for "quit\n"
, or strip
ping the lines.
Finally, even if you fix all of these problems, you're still waiting forever before doing anything. readlines
returns a list
of lines. The only way it can possibly do that is by reading all of the lines that will ever be on stdin
. You can't even start looping until you've read all those lines.
When standard input is a file, that happens when the file ends, so it's not too terrible. But when standard input is the Windows command prompt, the command prompt never ends.* So, this takes forever. You don't get to start processing the list of lines, because it takes forever to wait for the list of lines.
The solution is to not use readlines()
. Really, there is never a good reason to call readlines()
on anything, stdin
or not. Anything that readlines
works on is already an iterable full of lines, just like the list
that readlines
would give you, except that it's "lazy": it can give you the lines one at a time, instead of waiting and giving you all of them at once. (And even if you really need the list, just do list(f)
instead of f.readlines()
.)
So, instead of for line in sys.stdin.readlines():
, just do for line in sys.stdin:
(Or, better, replace the explicit loop completely and use a sequence of iterator transformations, as in mgilson's answer.)
The fixes JBernardo, Wing Tang Wong, etc. proposed are all correct, and necessary. The reason none of them fixed your problems is that if you have 4 bugs and fix 1, your code still doesn't work. That's exactly why "doesn't work" isn't a useful measure of anything in programming, and you have to debug what's actually going wrong to know whether you're making progress.
* I lied a bit about stdin
never being finished. If you type a control-Z (you may or may not need to follow it with a return), then stdin
is finished. But if your assignment is to make it quit as soon as the user types "quit"< turning in something that only quits when the user types "quit" and then return, control-Z, return again probably won't be considered successful.
'quit' != 'quit\n'
– Unknownline
will have a'\n'
on the end, so you won't ever hit therun = False
condition. – Rostandsys.stdin.readlines()
. That returns alist
of lines. Obviously it can't make thatlist
until it has all the lines, which means it can't return until you close standard input. The solution to that is to just… not callreadlines()
. It's certainly possible that you have a new problem after solving that one, just as you had a new problem after fixing the one JBernardo showed, but that doesn't mean this isn't a problem you need to fix. – Indecipherable