简体   繁体   中英

How to get user input during a while loop without blocking

I'm trying to write a while loop that constantly updates the screen by using os.system("clear") and then printing out a different text message every few seconds. How do I get user input during the loop? raw_input() just pauses and waits, which is not the functionality I want.

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)

I would like to be able to press 'q' or 'p' in the middle to quit and pause respectively.

The select module in Python's standard library may be what you're looking for -- standard input has FD 0, though you may also need to put a terminal in "raw" (as opposed to "cooked") mode, on unix-y systems, to get single keypresses from it as opposed to whole lines complete with line-end. If on Windows, msvcrt , also in Python standard library, has all the functionality you need -- msvcrt.kbhit() tells you if any keystroke is pending, and, if so, msvcrt.getch() tells you what character it is.

您还可以查看其中一个可用的配方 ,它为您提供了Unix和Windows所需的功能。

You can do that with threads, here is a basic example :

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

As usual, using threads is tricky, so be sure you understand what you do before coding that.

Warning : Queue will be rename in queue in Python 3.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM