我有一个脚本在调用时连续运行,每 5 分钟检查一次我的 gmail 收件箱。为了让它每 5 分钟运行一次,我使用了 time.sleep() 函数。但是,我希望用户在我按下 q 的任何时候结束脚本,这在使用 time.sleep() 时似乎无法完成。关于我如何做到这一点的任何建议?
阿里
我有一个脚本在调用时连续运行,每 5 分钟检查一次我的 gmail 收件箱。为了让它每 5 分钟运行一次,我使用了 time.sleep() 函数。但是,我希望用户在我按下 q 的任何时候结束脚本,这在使用 time.sleep() 时似乎无法完成。关于我如何做到这一点的任何建议?
阿里
您可以在 sys.stdin 上使用select()并结合超时。粗略地说,您的主循环将如下所示(未经测试):
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
为了能够从标准输入读取单个字符,您需要将标准输入置于无缓冲模式。此处描述了一种替代方法。如果您想保持简单,只需要求用户在“q”后按回车键
我之前提到的 -u 标志不起作用:它可能会将 pyton 置于无缓冲模式,但不会将您的终端置于无缓冲模式。
或者,ncursus 在这里可能会有所帮助。我只是在暗示,我对此没有太多经验;如果我想要一个花哨的用户界面,我会使用 TkInter。
好的。试试这个 python 代码......(在 linux 中测试。很可能不会在 Windows 上工作 - 感谢 Aaron 的输入)
这是从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'
如果您真的想要(并且想要浪费大量资源),您可以将循环切成 200 毫秒的块。所以睡 200 毫秒,检查输入,重复直到五分钟,然后检查你的收件箱。不过,我不会推荐它。
但是,当它处于睡眠状态时,该进程被阻塞并且在睡眠结束之前不会接收输入。
哦,作为补充说明,如果你在它睡眠时按下键,它仍然应该进入缓冲区,所以当睡眠结束并最终读取输入时,它会被拉出,IIRC。