web-dev-qa-db-fra.com

Python 3 entrées temporisées

Ce que j'aimerais pouvoir faire, c'est poser une question à un utilisateur en utilisant la saisie. Par exemple:

print('some scenario')
Prompt = input("You have 10 seconds to choose the correct answer...\n")

puis si le temps s'est écoulé, imprimez quelque chose comme

print('Sorry, times up.')

Toute aide me pointant dans la bonne direction serait grandement appréciée.

25
cloud311

Problème intéressant, cela semble fonctionner:

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 = raw_input("Input something: ")
12
mediocrity

S'il est acceptable de bloquer le thread principal lorsque l'utilisateur n'a pas fourni de réponse:

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()

Sinon, vous pourriez utiliser @ Alex Martelli's answer (modifié pour Python 3) sous Windows (non testé):

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] == '\n':   #XXX check what Windows returns here
                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)

Sous Unix, vous pouvez essayer:

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

Ou:

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
19
jfs