Entrada de teclado con tiempo de espera en Python
timeout keyboard-input (9)
¿Cómo solicitaría al usuario alguna información, pero el tiempo de espera después de N segundos?
Google apunta a un hilo de correo sobre esto en http://mail.python.org/pipermail/python-list/2006-January/533215.html pero parece que no funciona. La declaración en la que ocurre el tiempo de espera, sin importar si es una sys.input.readline o timer.sleep (), siempre obtengo:
<tipo ''exceptions.TypeError''>: [raw_] input esperado como máximo 1 argumentos, got 2
que de alguna manera el excepto no logra atrapar.
De forma análoga a la de Locane para Windows:
import subprocess
subprocess.call(''timeout /T 30'')
El ejemplo al que se ha vinculado es incorrecto y la excepción se produce cuando se llama al manejador de alarma en lugar de cuando se leen bloques. Mejor prueba esto:
import signal
TIMEOUT = 5 # number of seconds your want for timeout
def interrupted(signum, frame):
"called when read times out"
print ''interrupted!''
signal.signal(signal.SIGALRM, interrupted)
def input():
try:
print ''You have 5 seconds to type in your stuff...''
foo = raw_input()
return foo
except:
# timeout
return
# set alarm
signal.alarm(TIMEOUT)
s = input()
# disable the alarm after success
signal.alarm(0)
print ''You typed'', s
El siguiente código funcionó para mí.
Usé dos hilos uno para obtener el raw_Input y otro para esperar un tiempo específico. Si alguno de los hilos sale, ambos terminan y se devuelven.
def _input(msg, q):
ra = raw_input(msg)
if ra:
q.put(ra)
else:
q.put("None")
return
def _slp(tm, q):
time.sleep(tm)
q.put("Timeout")
return
def wait_for_input(msg="Press Enter to continue", time=10):
q = Queue.Queue()
th = threading.Thread(target=_input, args=(msg, q,))
tt = threading.Thread(target=_slp, args=(time, q,))
th.start()
tt.start()
ret = None
while True:
ret = q.get()
if ret:
th._Thread__stop()
tt._Thread__stop()
return ret
return ret
print time.ctime()
t= wait_for_input()
print "/nResponse :",t
print time.ctime()
La respuesta de Pablo no funcionó del todo. Código modificado a continuación que funciona para mí en
Windows 7 x64
shell CMD de vanilla (por ejemplo, no git-bash u otro shell que no sea M $)
- nada
msvcrt
funciona en git-bash aparece.Python 3.6
(Estoy publicando una nueva respuesta, porque la edición de la respuesta de Paul directamente lo cambiaría de Python 2.x -> 3.x, que parece demasiado para una edición (py2 todavía está en uso)
import sys, time, msvcrt
def readInput( caption, default, timeout = 5):
start_time = time.time()
sys.stdout.write(''%s(%s):''%(caption, default))
sys.stdout.flush()
input = ''''
while True:
if msvcrt.kbhit():
byte_arr = msvcrt.getche()
if ord(byte_arr) == 13: # enter_key
break
elif ord(byte_arr) >= 32: #space_char
input += "".join(map(chr,byte_arr))
if len(input) == 0 and (time.time() - start_time) > timeout:
print("timing out, using default value.")
break
print('''') # needed to move to next line
if len(input) > 0:
return input
else:
return default
# and some examples of usage
ans = readInput(''Please type a name'', ''john'')
print( ''The name is %s'' % ans)
ans = readInput(''Please enter a number'', 10 )
print( ''The number is %s'' % ans)
No es una solución de Python, pero ...
Corrí a este problema con un script que se ejecuta bajo CentOS (Linux), y lo que funcionó para mi situación fue simplemente ejecutar el comando Bash "leer -t" en un subproceso. Hack asqueroso brutal, lo sé, pero me siento lo suficientemente culpable de lo bien que funcionó que quería compartirlo con todos los que están aquí.
import subprocess
subprocess.call(''read -t 30'', shell=True)
Todo lo que necesitaba era algo que esperó durante 30 segundos a menos que se presionara la tecla ENTER. Esto funcionó muy bien.
Pasé unos veinte minutos más o menos sobre esto, así que pensé que valía la pena intentarlo aquí. Sin embargo, se está construyendo directamente a partir de la respuesta del usuario137673. Me pareció más útil hacer algo como esto:
#! /usr/bin/env python
import signal
timeout = None
def main():
inp = stdinWait("You have 5 seconds to type text and press <Enter>... ", "[no text]", 5, "Aw man! You ran out of time!!")
if not timeout:
print "You entered", inp
else:
print "You didn''t enter anything because I''m on a tight schedule!"
def stdinWait(text, default, time, timeoutDisplay = None, **kwargs):
signal.signal(signal.SIGALRM, interrupt)
signal.alarm(time) # sets timeout
global timeout
try:
inp = raw_input(text)
signal.alarm(0)
timeout = False
except (KeyboardInterrupt):
printInterrupt = kwargs.get("printInterrupt", True)
if printInterrupt:
print "Keyboard interrupt"
timeout = True # Do this so you don''t mistakenly get input when there is none
inp = default
except:
timeout = True
if not timeoutDisplay is None:
print timeoutDisplay
signal.alarm(0)
inp = default
return inp
def interrupt(signum, frame):
raise Exception("")
if __name__ == "__main__":
main()
Una respuesta tardía :)
Haría algo como esto:
from time import sleep
print(''Please provide input in 20 seconds! (Hit Ctrl-C to start)'')
try:
for i in range(0,20):
sleep(1) # could use a backward counter to be preeety :)
print(''No input is given.'')
except KeyboardInterrupt:
raw_input(''Input x:'')
print(''You, you! You know something.'')
Sé que esto no es lo mismo, pero muchos problemas de la vida real podrían resolverse de esta manera. (Por lo general, necesito tiempo de espera para la entrada del usuario cuando quiero que algo continúe ejecutándose si el usuario no está allí en este momento).
Espero que esto al menos parcialmente ayude. (Si alguien lo lee de todos modos :))
Usar una llamada de selección es más corto, y debería ser mucho más portátil
import sys, select
print "You have ten seconds to answer!"
i, o, e = select.select( [sys.stdin], [], [], 10 )
if (i):
print "You said", sys.stdin.readline().strip()
else:
print "You said nothing!"
Y aquí hay uno que funciona en Windows
No he podido obtener ninguno de estos ejemplos para trabajar en Windows, así que he combinado algunas respuestas diferentes de para obtener lo siguiente:
import threading, msvcrt
import sys
def readInput(caption, default, timeout = 5):
class KeyboardThread(threading.Thread):
def run(self):
self.timedout = False
self.input = ''''
while True:
if msvcrt.kbhit():
chr = msvcrt.getche()
if ord(chr) == 13:
break
elif ord(chr) >= 32:
self.input += chr
if len(self.input) == 0 and self.timedout:
break
sys.stdout.write(''%s(%s):''%(caption, default));
result = default
it = KeyboardThread()
it.start()
it.join(timeout)
it.timedout = True
if len(it.input) > 0:
# wait for rest of input
it.join()
result = it.input
print '''' # needed to move to next line
return result
# and some examples of usage
ans = readInput(''Please type a name'', ''john'')
print ''The name is %s'' % ans
ans = readInput(''Please enter a number'', 10 )
print ''The number is %s'' % ans