This happens because your computer registers the key strokes and on the console, those are made available on the stdin
input stream.
If you save your script as test.py
and run python test.py
and start entering some keystrokes, like abc
, those letters will be on standard input.
Your script doesn't read them, because it doesn't touch that stream, as you're not using input()
or any other calls that would read that stream. So your script finishes, the characters are still on standard input, the prompt comes back and it reads those characters, with the given result:
Hello
Hello
Hello
PS C:\Users\username> abc
To avoid this, you can read / flush the input buffer at the end of your script. However, this is surprisingly hard if you need it to work across all operating systems and in different modes of running your script (directly from cmd, IDLE, in other IDEs, etc.)
The problem is there's no way to know if there's input on the standard input stream, until you try to read from it. But if you try to read from it, your script will pause until an 'end of line' or 'end of file' is received. And if the user is just hitting keys, that won't happen, so you'll end up reading until they hit something like Ctrl+Break or Ctrl+C.
Here's a way I think is relatively robust, but I recommend you test it in scenarios and environments you consider likely for use of your script:
import sys
import threading
import queue
import os
import signal
for _ in range(100000):
print("Hello")
timeout = 0.1 # sec
def no_input():
# stop main thread (which is probably blocked reading input) via an interrupt signal
# only available for windows in Python version 3.2 or higher
os.kill(os.getpid(), signal.SIGINT)
exit()
# if a sigint is received, exit the main thread (you could call another function to do work first and then exit()
signal.signal(signal.SIGINT, exit)
# input is stored here, until it's dealt with
input_queue = queue.Queue()
# read all available input until main thread exit
def get_input():
while True:
try:
# read input, not doing anything with it
_ = input_queue.get(timeout=timeout)
except queue.Empty:
no_input()
reading_thread = threading.Thread(target=get_input)
reading_thread.start()
# main loop: put any available input in the queue, will wait for input if there is none
for line in sys.stdin:
input_queue.put(line)
# wait for reading thread
reading_thread.join()
It basically reads the input from a second thread, allowing that the main thread to get the input and possibly do something with it until there's nothing left and then it just tells the main thread to exit. Note that this will result in your script exiting with an exit code of 2, which may not be what you want.
Also note that you'll still see the input on screen, but it will no longer be passed to the terminal:
Hello
Hello
Hello
abc
PS C:\Users\username>
I don't know if there's an easy way to avoid the echo, other than on Linux doing something like stty -echo
. You could of course just call the system to clear the screen at the end of your script:
from subprocess import call
from os import name as os_name
call('clear' if os_name =='posix' else 'cls')