Time-Limited Input?
Solution 1
Interesting problem, this seems to work:
import time
from threading import Thread
answer = None
def check():
time.sleep(2)
if answer != None:
return
print("Too Slow")
Thread(target = check).start()
answer = input("Input something: ")
Solution 2
If it is acceptable to block the main thread when user haven't provided an answer:
from threading import Timer
timeout = 10
t = Timer(timeout, print, ['Sorry, times up'])
t.start()
prompt = "You have %d seconds to choose the correct answer...\n" % timeout
answer = input(prompt)
t.cancel()
Otherwise, you could use @Alex Martelli's answer (modified for Python 3) on Windows (not tested):
import msvcrt
import time
class TimeoutExpired(Exception):
pass
def input_with_timeout(prompt, timeout, timer=time.monotonic):
sys.stdout.write(prompt)
sys.stdout.flush()
endtime = timer() + timeout
result = []
while timer() < endtime:
if msvcrt.kbhit():
result.append(msvcrt.getwche()) #XXX can it block on multibyte characters?
if result[-1] == '\r':
return ''.join(result[:-1])
time.sleep(0.04) # just to yield to other processes/threads
raise TimeoutExpired
Usage:
try:
answer = input_with_timeout(prompt, 10)
except TimeoutExpired:
print('Sorry, times up')
else:
print('Got %r' % answer)
On Unix you could try:
import select
import sys
def input_with_timeout(prompt, timeout):
sys.stdout.write(prompt)
sys.stdout.flush()
ready, _, _ = select.select([sys.stdin], [],[], timeout)
if ready:
return sys.stdin.readline().rstrip('\n') # expect stdin to be line-buffered
raise TimeoutExpired
Or:
import signal
def alarm_handler(signum, frame):
raise TimeoutExpired
def input_with_timeout(prompt, timeout):
# set signal handler
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(timeout) # produce SIGALRM in `timeout` seconds
try:
return input(prompt)
finally:
signal.alarm(0) # cancel alarm
cloud311
I am new to programming, and am tring to learn Python as my first language. I'm not sure if I want to pursue a career in programming yet, but I do enjoy problem solving. I currently have a job that will allow me to experiment with writing some text processing scripts. I joined stack overflow so I could talk to and learn from people in the community that don't mind helping beginning programmers.
Updated on October 04, 2021Comments
-
cloud311 over 2 years
What I would like to be able to do is ask a user a question using input. For example:
print('some scenario') prompt = input("You have 10 seconds to choose the correct answer...\n")
and then if the time elapses print something like
print('Sorry, times up.')
Any help pointing me in the right direction would be greatly appreciated.
-
jfs about 11 yearsyou could use
threading.Timer
instead ofThread
+time.sleep
. There is noraw_input
in Python 3. -
Eliezer Miron almost 8 yearsFirst answer did print after a timeout, but the input was still available.
-
DevPlayer over 7 yearsHow does raw_input() terminate in the mainthread? I see how thread check() ends and pushes "Too slow" to stdout. But not how raw_input() gets its stdin buffer filled or "completes".
-
jfs over 7 years@EliezerMiron: yes, the
input()
call is not interrupted in the first example that is why there is: "If it is acceptable to block the main thread" before the example. If you need to interrtupt the input, use the following examples withinput_with_timeout()
. -
Pro Q about 7 yearsI tried using the
import signal
one, and its sense of timing appears to be way off. I'm using Cloud9 IDE. If I give it a .5 timeout, it will wait about 3 seconds before timing out. -
abarnert almost 6 yearsThis (a) isn't Python 3, and (b) doesn't work, for the reason @DevPlayer pointed out.
-
Akaisteph7 almost 5 yearsWhy was this accepted?
-
Dmitri Nesteruk over 3 yearsThis should not have been accepted, it doesn't terminate.
-
DannyTalent about 3 yearsFor the windows option, you may want to replace
if result[-1] == '\n':
forif result[-1] == '\r':
(tested on vscode, pwshell, cmd and terminal app) -
Julian almost 3 yearsCouple of things on the Windows version. You may want to
print()
before youreturn
. Also, if you want to (kind-of) support backspace, you want another branch:if ord(result[-1]) == 8: result = result[:-2]
. Tested in PyCharm console. -
stucash about 2 yearsthe *nix version does not work for me ; one thing I was asked to pause the process to use input prompt when I was in debug mode in Pycharm; another thing was the timer simply ignored my input even if I entered a valid input before time was up.