使用空格键中断计时器

Interrupting a timer with spacebar

假设我想计算我能屏住呼吸的时间,我想用 Python 来计算。我有短脚本:

start = time()
try:
    while True: pass
except KeyboardInterrupt:
    print(time() - start)

这具有我想要的基本功能,但它有一个致命的缺点。屏住呼吸时间长了,脑子可能会有些模糊,可能会找不到合适的位置马上按Ctrl+c,可能会丢失训练的重要数据。

空格键更容易命中。有没有一种简单的方法可以让我按下它时循环停止?

编辑:我在 OSX

您需要将控制台的键盘 (pty) 驱动程序置于原始模式。 在这个答案中有解释:

大量引用该答案:

#! /usr/bin/env python3
import sys
import termios
import time
import tty


def hold_breath(fin):
    orig_setting = termios.tcgetattr(fin)
    tty.setraw(fin)
    start = time.time()
    try:
        ch = fin.read(1)[0]
        assert ch == ' '
    finally:
        print('You lasted %.03f seconds.\r' % (time.time() - start))
        termios.tcsetattr(fin, termios.TCSADRAIN, orig_setting)


if __name__ == '__main__':
    print('Hit space.')
    hold_breath(sys.stdin)

在 OS/X 和 Linux 上工作正常。如果您在程序恢复原始设置之前中断程序,那么 $ stty sane 就是您的朋友。

import sys                                                                          
import termios                                                                      
import contextlib                                                                   

SPACE_BAR = 32                                                                      

@contextlib.contextmanager                                                       
def raw_mode(file):                                                                 
    old_attrs = termios.tcgetattr(file.fileno())                                    
    new_attrs = old_attrs[:]                                                        
    new_attrs[3] = new_attrs[3] & ~(termios.ECHO | termios.ICANON)                  
    try:                                                                            
        termios.tcsetattr(file.fileno(), termios.TCSADRAIN, new_attrs)              
        yield                                                                       
    finally:                                                                        
        termios.tcsetattr(file.fileno(), termios.TCSADRAIN, old_attrs)              


def main():                                                                         
    print 'exit with spacebar'                                                      
    with raw_mode(sys.stdin):                                                       
        try:                                                                        
            while True:                                                          
                if sys.stdin.read(1) == chr(SPACE_BAR):                          
                    break                                                        

        except (KeyboardInterrupt, EOFError):                                    
            pass                                                                 


if __name__ == '__main__':                                                       
    main()                 

答案取决于您的OS。在 Windows 上,这将在任何按键按下时停止,但您可以查看 msvcrt.getch() 的 return 值以确定它是否为 space。现在当你昏倒并且你的脸碰到键盘时它会停止在任何键上。

import time
import msvcrt
start = time.time()
while not msvcrt.kbhit():  # Indicates a key is waiting to be read
    pass
end = time.time()
msvcrt.getch()  # read and (in this case) throw away the key press.
print(end-start)