en python, existe-t-il un moyen de compter le temps pendant l'attente d'une entrée utilisateur afin qu'après, par exemple, 30 secondes, la fonction raw_input()
soit automatiquement ignorée?
La fonction signal.alarm , sur laquelle est basée la solution recommandée par @ jer, est malheureusement uniquement sous Unix. Si vous avez besoin d'une solution multiplate-forme ou spécifique à Windows, vous pouvez vous baser sur threading.Timer , utilisez thread.interrupt_main pour envoyer une KeyboardInterrupt
au thread principal à partir du thread du minuteur. C'est à dire.:
import thread
import threading
def raw_input_with_timeout(Prompt, timeout=30.0):
print Prompt,
timer = threading.Timer(timeout, thread.interrupt_main)
astring = None
try:
timer.start()
astring = raw_input(Prompt)
except KeyboardInterrupt:
pass
timer.cancel()
return astring
cela retournera None, que le délai expire après 30 secondes ou que l'utilisateur décide explicitement de frapper control-C pour abandonner quoi que ce soit, mais il semble correct de traiter les deux cas de la même manière (si vous avez besoin de distinguer, vous pouvez utiliser pour le minuteur, une fonction de votre choix qui, avant d’interrompre le fil principal, enregistre quelque part le fait qu’un délai a expiré a, et dans votre gestionnaire pour KeyboardInterrupt
accéder à "quelque part" pour distinguer lequel des deux cas eu lieu).
Edit : J'aurais juré que cela fonctionnait mais j'ai dû me tromper - le code ci-dessus omet le timer.start()
, et de toute évidence, même avec cela, je ne peux pas le faire fonctionner. pas plus. select.select
serait une autre chose évidente à essayer, mais cela ne fonctionnera pas sur un "fichier normal" (y compris stdin) sous Windows. Sous Unix, cela fonctionne sur tous les fichiers, sous Windows, uniquement sur les sockets.
Donc, je ne sais pas comment faire une "entrée brute avec timeout" multiplate-forme. Un fichier spécifique à Windows peut être construit avec une scrutation serrée en boucle msvcrt.kbhit , en effectuant un msvcrt.getche
(et en vérifiant s’il s’agit d’un retour indiquant la sortie effectuée. continue d’attendre) et en vérifiant le délai si nécessaire. Je ne peux pas tester parce que je n'ai pas de machine Windows (ce sont tous des Mac et Linux), mais ici, le code non testé je suggérerais:
import msvcrt
import time
def raw_input_with_timeout(Prompt, timeout=30.0):
print Prompt,
finishat = time.time() + timeout
result = []
while True:
if msvcrt.kbhit():
result.append(msvcrt.getche())
if result[-1] == '\r': # or \n, whatever Win returns;-)
return ''.join(result)
time.sleep(0.1) # just to yield to other processes/threads
else:
if time.time() > finishat:
return None
Dans un commentaire, l'OP dit qu'il ne veut pas return None
à l'expiration du délai, mais quelle est l'alternative? Relever une exception? Renvoyer une valeur par défaut différente? Quelle que soit l’alternative qu’il recherche, il peut clairement le mettre à la place de mon return None
;-).
Si vous ne voulez pas expirer juste parce que l'utilisateur est en train de taper lentement (plutôt que de ne pas taper du tout! -), vous pouvez recalculer le résultat après chaque saisie de caractère réussie.
J'ai trouvé une solution à ce problème dans un article de blog . Voici le code de cet article de blog:
import signal
class AlarmException(Exception):
pass
def alarmHandler(signum, frame):
raise AlarmException
def nonBlockingRawInput(Prompt='', timeout=20):
signal.signal(signal.SIGALRM, alarmHandler)
signal.alarm(timeout)
try:
text = raw_input(Prompt)
signal.alarm(0)
return text
except AlarmException:
print '\nPrompt timeout. Continuing...'
signal.signal(signal.SIGALRM, signal.SIG_IGN)
return ''
Remarque: ce code ne fonctionnera que sur les systèmes d'exploitation * nix .
from threading import Timer
def input_with_timeout(x):
def time_up():
answer= None
print 'time up...'
t = Timer(x,time_up) # x is amount of time in seconds
t.start()
try:
answer = input("enter answer : ")
except Exception:
print 'pass\n'
answer = None
if answer != True: # it means if variable have somthing
t.cancel() # time_up will not execute(so, no skip)
input_with_timeout(5) # try this for five seconds
Comme il est auto-défini ... lancez-le en ligne de commande Invite, j'espère que vous obtiendrez la réponse Lisez ceci python doc vous saurez parfaitement ce qui vient de se passer dans ce code!
La fonction input () est conçue pour attendre que l'utilisateur entre quelque chose (au moins la touche [Entrée]).
Si vous n’êtes pas prêt à utiliser input (), vous trouverez ci-dessous une solution beaucoup plus légère avec tkinter. Dans tkinter, les boîtes de dialogue (et tout widget) peuvent être détruites après un temps donné.
Voici un exemple :
import tkinter as tk
def W_Input (label='Input dialog box', timeout=5000):
w = tk.Tk()
w.title(label)
W_Input.data=''
wFrame = tk.Frame(w, background="light yellow", padx=20, pady=20)
wFrame.pack()
wEntryBox = tk.Entry(wFrame, background="white", width=100)
wEntryBox.focus_force()
wEntryBox.pack()
def fin():
W_Input.data = str(wEntryBox.get())
w.destroy()
wSubmitButton = tk.Button(w, text='OK', command=fin, default='active')
wSubmitButton.pack()
# --- optionnal extra code in order to have a stroke on "Return" equivalent to a mouse click on the OK button
def fin_R(event): fin()
w.bind("<Return>", fin_R)
# --- END extra code ---
w.after(timeout, w.destroy) # This is the KEY INSTRUCTION that destroys the dialog box after the given timeout in millisecondsd
w.mainloop()
W_Input() # can be called with 2 parameter, the window title (string), and the timeout duration in miliseconds
if W_Input.data : print('\nYou entered this : ', W_Input.data, end=2*'\n')
else : print('\nNothing was entered \n')
Un exemple de malédiction qui prend pour un test mathématique chronométré
#!/usr/bin/env python3
import curses
import curses.ascii
import time
#stdscr = curses.initscr() - Using curses.wrapper instead
def main(stdscr):
hd = 100 #Timeout in tenths of a second
answer = ''
stdscr.addstr('5+3=') #Your Prompt text
s = time.time() #Timing function to show that solution is working properly
while True:
#curses.echo(False)
curses.halfdelay(hd)
start = time.time()
c = stdscr.getch()
if c == curses.ascii.NL: #Enter Press
break
Elif c == -1: #Return on timer complete
break
Elif c == curses.ascii.DEL: #Backspace key for corrections. Could add additional hooks for cursor movement
answer = answer[:-1]
y, x = curses.getsyx()
stdscr.delch(y, x-1)
Elif curses.ascii.isdigit(c): #Filter because I only wanted digits accepted
answer += chr(c)
stdscr.addstr(chr(c))
hd -= int((time.time() - start) * 10) #Sets the new time on getch based on the time already used
stdscr.addstr('\n')
stdscr.addstr('Elapsed Time: %i\n'%(time.time() - s))
stdscr.addstr('This is the answer: %s\n'%answer)
#stdscr.refresh() ##implied with the call to getch
stdscr.addstr('Press any key to exit...')
curses.wrapper(main)
sous Linux, on pourrait utiliser curses et la fonction getch, son blocage. voir getch ()
https://docs.python.org/2/library/curses.html
fonction qui attend la saisie au clavier pendant x secondes (vous devez d’abord initialiser une fenêtre curses (win1)!
import time
def tastaturabfrage():
inittime = int(time.time()) # time now
waitingtime = 2.00 # time to wait in seconds
while inittime+waitingtime>int(time.time()):
key = win1.getch() #check if keyboard entry or screen resize
if key == curses.KEY_RESIZE:
empty()
resize()
key=0
if key == 118:
p(4,'KEY V Pressed')
yourfunction();
if key == 107:
p(4,'KEY K Pressed')
yourfunction();
if key == 99:
p(4,'KEY c Pressed')
yourfunction();
if key == 120:
p(4,'KEY x Pressed')
yourfunction();
else:
yourfunction
key=0