в python, есть ли способ, ожидая ввода пользователя, подсчитать время, чтобы, скажем, через 30 секунд функция raw_input()
автоматически пропускалась?
Как установить ограничение по времени для raw_input
Ответы (7)
Функция signal.alarm, в которой @ jer рекомендуемое решение основано, к сожалению, только для Unix. Если вам нужно кроссплатформенное решение или решение для Windows, вы можете основать его на threading.Timer вместо этого, используя thread.interrupt_main, чтобы отправить KeyboardInterrupt
в основной поток из потока таймера. То есть:
import thread
import threading
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
timer = threading.Timer(timeout, thread.interrupt_main)
astring = None
try:
timer.start()
astring = input(prompt)
except KeyboardInterrupt:
pass
timer.cancel()
return astring
это вернет None независимо от того, истечет ли 30-секундный тайм-аут или пользователь явно решит нажать control-C, чтобы отказаться от ввода чего-либо, но кажется нормально обрабатывать два случая одинаково (если вам нужно различать, вы можете использовать для таймера - ваша собственная функция, которая, прежде чем прерывать основной поток, где-то записывает факт, что истекло время ожидания , и в вашем обработчике для KeyboardInterrupt
доступа к этому "где-то", чтобы различать, какой из двух случаи имели место).
Изменить: я мог бы поклясться, что это сработало, но я, должно быть, ошибался - в приведенном выше коде отсутствуют явно необходимые timer.start()
, и, даже если с ними я не могу он больше не работает. Было бы очевидно, что лучше всего попробовать select.select
, но он не будет работать с «обычным файлом» (включая stdin) в Windows - в Unix он работает со всеми файлами, в Windows - только с сокетами.
Поэтому я не знаю, как сделать кроссплатформенный «необработанный ввод с таймаутом». Специфичный для Windows может быть создан с помощью опроса в узком цикле msvcrt .kbhit, выполняя msvcrt.getche
(и проверяя, является ли это возвратом, чтобы указать, что вывод выполнен, и в этом случае он выходит из цикла, в противном случае накапливается и продолжает ждать) и проверяет время ожидания, если это необходимо. Я не могу протестировать, потому что у меня нет компьютера с Windows (все они Mac и Linux), но вот непроверенный код, который я бы предложил:
import msvcrt
import time
def raw_input_with_timeout(prompt, timeout=30.0):
print(prompt, end=' ')
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
OP в комментарии говорит, что не хочет return None
по таймауту, но какова альтернатива? Вызывает исключение? Возвращаете другое значение по умолчанию? Какую бы альтернативу он ни пожелал, он явно может поставить ее вместо моего return None
;-).
Если вы не хотите тайм-аут только потому, что пользователь набирает медленно (а не совсем не печатает! -), вы можете пересчитывать finishat после каждого успешного ввода символа.
None
, добавьте его в качестве аргумента функции; Теперь я перекодировал его как только для Windows (но не могу протестировать, так как у меня нет Windows) и сделал так, чтобы он завершился через 30 секунд, даже если пользователь медленно набирает ( вместо того, чтобы ждать 30 секунд без набора текста, что мне кажется гораздо более разумным интерфейсом), хотя я также упоминаю, как легко перейти к более разумному поведению (вам просто нужно сбросить крайний срок после того, как каждый набранный символ будет успешно прочитан , поэтому всего 30 секунд бездействия приведет к тайм-ауту).
- person Alex Martelli; 29.05.2010
return None
на return 3.1415
, нет?
- person Alex Martelli; 29.05.2010
print prompt,
, который я пропустил - я только что отредактировал ответ, так что теперь он там (я не уверен, нужен ли вам sys.stdout.flush()
после него, а у меня нет Windows-машины, чтобы попробовать; - ).
- person Alex Martelli; 30.05.2010
Я нашел решение этой проблемы в сообщении в блоге а>. Вот код из этого сообщения в блоге:
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 ''
Обратите внимание: этот код будет работать только в ОС * nix.
Функция input () предназначена для ожидания, пока пользователь что-то введет (по крайней мере, клавишу [Enter]).
Если вы не настроены на использование input (), ниже представлено гораздо более легкое решение с использованием tkinter. В tkinter диалоговые окна (и любой виджет) могут быть уничтожены через определенное время.
Вот пример:
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')
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
Поскольку это самоопределение ... запустите его в командной строке, я надеюсь, вы получите ответ, прочтите это python doc вам будет кристально ясно, что только что произошло в этом коде !!
raw_input
следует использовать, а не input
(Python 2 обозначен print
). В time_up()
чтение не будет отменено, если в его конце не будет вызван os._exit(1)
. Это может иметь другие последствия, но избавиться от этого консольного чтения непросто.
- person cdarke; 26.08.2015
Пример проклятий, который можно использовать для теста по математике
#!/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)
под linux можно использовать функции curses и getch, не блокирующие их. см. getch ()
https://docs.python.org/2/library/curses.html
функция, которая ожидает ввода с клавиатуры в течение x секунд (сначала вы должны инициализировать окно 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
Это для более новых версий Python, но я считаю, что он все равно ответит на вопрос. Это создает сообщение пользователю о том, что время истекло, а затем завершает код. Я уверен, что есть способ заставить его пропустить ввод, а не полностью завершить код, но в любом случае это должно, по крайней мере, помочь ...
import sys
import time
from threading import Thread
import pyautogui as pag
#imports the needed modules
xyz = 1 #for a reference call
choice1 = None #sets the starting status
def check():
time.sleep(15)#the time limit set on the message
global xyz
if choice1 != None: # if choice1 has input in it, than the time will not expire
return
if xyz == 1: # if no input has been made within the time limit, then this message
# will display
pag.confirm(text = 'Time is up!', title = 'Time is up!!!!!!!!!')
sys.exit()
Thread(target = check).start()#starts the timer
choice1 = input("Please Enter your choice: ")