py30.png

Dočasné čekání na vstup

Vytaženo a upraveno z konference

Dotaz

Ahoj, potřebuji aby když uživatel neodpoví na výzvu input() do 5 sekund, aby čekání na odpověď skončilo a dosadila se nějaké defaultní hodnota.

Obecná odpověď

Zdravím, Nejjednodušší (a nejelegantnější) by bylo použití funkce alarm a obsluhy SIGALRM, ale to je možné pouze na rozumných OS, které vyhovují normě POSIX (což by správně měly všechny systémy, ale nic není ideální...). Další možností by bylo použití funkce select, ale to také na OS, který nejmenujeme, nepůjde (tam funguje select jen se sockety). Možná by šlo určitým způsobem využít nonblocking IO, ale to by nejspíš vyžadovalo pywin32 knihovny a nevím, jaká je úroveň podpory této funkce v technicky nedokonalých systémech. Řešení přes thready mi přijde docela komplikované a nespolehlivé, hlavně je otázkou přerušení raw_input funkce (možná by šlo použít něco jako externí interrupt vlákna, ale taktéž nevím, do jaké míry je tato funkce spolehlivá). Takže odpověď není jednoznačná, můžete vyzkoušet různé postupy, v případě zájmu o podrobnosti se ozvěte.

GUI

Ne, nepotrebujes input(), potrebujes od uzivatele nejak zadat hodnotu. Tohle upresneni je pomerne zasadni :). Preruseni input() muze byt IMHO totiz pomerne problematicke. Na Tvem miste bych zkusil pouzit nejaky toolkit pro vytvareni TUI (textovych user interface), treba (n)curses nebo slang nebo GUI (Tkinter, PyGTK, ...).

Windows

Není bez chyby, není takový jaký by měl, ale alespon neco. Jakmile napíšeš jediné písmeno, už není možno ukončit vlákno po zadané době. Problém totiž je, že nejde násilně ukončit vlákno, které čeká na obyčejném input()

import threading, queue, time
import msvcrt # Jen pro MS Windows

vystup = queue.Queue()
zamek = threading.Lock()

def vlakno1():
    time.sleep(5)
    vystup.put('konec')

def vlakno2():
    print ("Ocekavam vstup: ")
    while nasloucham.isAlive():
        if msvcrt.kbhit():
            zamek.acquire()
            vystup.put(input())
            zamek.release()

nasloucham = threading.Thread(target = vlakno1)
cekamvstup = threading.Thread(target = vlakno2)
nasloucham.start()
cekamvstup.start()
while nasloucham.isAlive() or not vystup.empty():
    if not zamek.locked() and not vystup.empty():
        print (vystup.get() )

Linux

Zaprvé píšu s křížkem po funuse a zadruhé tohle řešení bude fungovat jen na Operačních systémech, což už poznamenal regnarG. Takže si toho nevšímejte :-)

#!/usr/bin/python

import sys, select
r = select.select([sys.stdin], [], [], 5)
if r[0]:
     choice = sys.stdin.readline()
else:
     choice = 'default\n'
print 'Tvoje volba:', choice