Как получить пользовательский ввод во время цикла while без блокировки - PullRequest
2 голосов
/ 11 августа 2009

Я пытаюсь написать цикл while, который постоянно обновляет экран с помощью os.system («clear»), а затем распечатывает другое текстовое сообщение каждые несколько секунд. Как получить пользовательский ввод во время цикла? raw_input () просто делает паузу и ждет, а это не та функциональность, которую я хочу.

import os
import time

string = "the fox jumped over the lazy dog"
words = string.split(" ")
i = 0 

while 1:
    os.system("clear")
    print words[i]
    time.sleep(1)
    i += 1
    i = i%len(words)

Я хотел бы иметь возможность нажимать 'q' или 'p' в середине, чтобы выйти и сделать паузу соответственно.

Ответы [ 3 ]

9 голосов
/ 11 августа 2009

Модуль select в стандартной библиотеке Python может быть тем, что вы ищете - стандартный ввод имеет FD 0, хотя вам также может понадобиться поместить терминал в «raw» (в отличие от « режим "cooked") в системах unix-y, чтобы получать от нее единичные нажатия клавиш, а не целые строки с завершением строки. Если в Windows msvcrt , также в стандартной библиотеке Python, имеет всю необходимую функциональность - msvcrt.kbhit() сообщает вам, ожидает ли какое-либо нажатие клавиши, и, если да, msvcrt.getch() сообщает вам, какой символ это есть.

3 голосов
/ 11 августа 2009

Вы также можете проверить один из доступных там рецептов , который дает вам функциональность, которую вы ищете как для Unix, так и для Windows.

1 голос
/ 11 августа 2009

Вы можете сделать это с потоками, вот базовый пример:

import threading, os, time, itertools, Queue

# setting a cross platform getch like function
# thks to the Python Cookbook
# why isn't standard on this battery included language ?
try : # on windows
    from msvcrt import getch
except ImportError : # on unix like systems
    import sys, tty, termios
    def getch() :
        fd = sys.stdin.fileno()
        old_settings = termios.tcgetattr(fd)
        try :
            tty.setraw(fd)
            ch = sys.stdin.read(1)
        finally :
            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
        return ch

# this will allow us to communicate between the two threads
# Queue is a FIFO list, the param is the size limit, 0 for infinite
commands = Queue.Queue(0)

# the thread reading the command from the user input     
def control(commands) :

    while 1 :

        command = getch()
        commands.put(command) # put the command in the queue so the other thread can read it

        #  don't forget to quit here as well, or you will have memory leaks
        if command == "q" :
            break


# your function displaying the words in an infinite loop
def display(commands):

    string = "the fox jumped over the lazy dog"
    words = string.split(" ")
    pause = False 
    command = ""

    # we create an infinite generator from you list
    # much better than using indices
    word_list = itertools.cycle(words) 

    # BTW, in Python itertools is your best friend

    while 1 :

        # parsing the command queue
        try:
           # false means "do not block the thread if the queue is empty"
           # a second parameter can set a millisecond time out
           command = commands.get(False) 
        except Queue.Empty, e:
           command = ""

        # behave according to the command
        if command == "q" :
            break

        if command == "p" :
            pause = True

        if command == "r" :
            pause = False

        # if pause is set to off, then print the word
        # your initial code, rewritten with a generator
        if not pause :
            os.system("clear")
            print word_list.next() # getting the next item from the infinite generator 

        # wait anyway for a second, you can tweak that
        time.sleep(1)



# then start the two threads
displayer = threading.Thread(None, # always to None since the ThreadGroup class is not implemented yet
                            display, # the function the thread will run
                            None, # doo, don't remember and too lazy to look in the doc
                            (commands,), # *args to pass to the function
                             {}) # **kwargs to pass to the function

controler = threading.Thread(None, control, None, (commands,), {})

if __name__ == "__main__" :
    displayer.start()
    controler.start()

Как обычно, использование потоков сложно, поэтому убедитесь, что вы понимаете, что делаете, прежде чем кодировать это.

Предупреждение: очередь будет переименована в очередь в Python 3.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...