简体   繁体   中英

Continous loop and exiting in python

I have a script that runs continuously when invoked and every 5 minutes checks my gmail inbox. To get it to run every 5 minutes I am using the time.sleep() function. However I would like user to end the script anytime my pressing q, which it seems cant be done when using time.sleep(). Any suggestions on how i can do this?

Ali

You can use select() on sys.stdin combined with a timeout. Roughly speaking, your main loop will look like this (untested):

while True:
    r,w,e = select.select([sys.stdin], [], [], 600)
    if sys.stdin in r: # data available on sys.stdin
        if sys.stdin.read() == 'q':
            break
    # do gmail stuff

To be able to read a single character from stdin you will need to put stdin in unbuffered mode. An alternative is described here . If you want to keep things simple, just require the user to hit enter after the 'q'

The -u flag I mentioned earlier won't work: it may put pyton in unbuffered mode but not your terminal.

Alternatively, ncursus may be of help here. I'm merely hinting, I don't have much experience with this; if I want a fancy user interface, I'd use TkInter.

Ok. try this python code... (Tested in linux. Most probably wont work on Windows - thanks to Aaron's input on that)

This is derived (copied and modified) from http://code.activestate.com/recipes/572182-how-to-implement-kbhit-on-linux/


import sys, termios, atexit
from select import select

delay = 1 # in seconds - change this for your needs

# save the terminal settings
fd = sys.stdin.fileno()
new_term = termios.tcgetattr(fd)
old_term = termios.tcgetattr(fd)

# new terminal setting unbuffered
new_term[3] = (new_term[3] & ~termios.ICANON & ~termios.ECHO)

# switch to normal terminal
def set_normal_term():
    termios.tcsetattr(fd, termios.TCSAFLUSH, old_term)

# switch to unbuffered terminal
def set_curses_term():
    termios.tcsetattr(fd, termios.TCSAFLUSH, new_term)

def getch():
    return sys.stdin.read(1)

def kbhit():
    dr,dw,de = select([sys.stdin], [], [], delay)
    return dr <> []

def check_mail():
    print 'Checking mail'

if __name__ == '__main__':
    atexit.register(set_normal_term)
    set_curses_term()

    while 1:
        if kbhit():
            ch = getch()
            break
        check_mail()

    print 'done'

If you really wanted to (and wanted to waste a lot of resources), you could cut your loop into 200 ms chunks. So sleep 200 ms, check input, repeat until five minutes elapse, and then check your inbox. I wouldn't recommend it, though.

While it's sleeping, though, the process is blocked and won't receive input until the sleep ends.

Oh, as an added note, if you hit the key while it's sleeping, it should still go into the buffer, so it'll get pulled out when the sleep ends and input is finally read, IIRC.

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