python timeout keyboard-input

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