暂停命令行python程序的简单方法?

2 投票
3 回答
2633 浏览
提问于 2025-04-16 05:13

假设我有一个Python程序,它会输出一些文本,比如:

while 1:
  print "This is a line"

有没有简单的方法让我们可以按下键盘上的一个键来暂停这个循环,然后再按一次键继续运行——但如果什么都不按,它就应该自动继续?

我希望不需要使用像curses这样的复杂东西来实现这个功能!

3 个回答

0

当你按下 Ctrl+C 时,你的程序会抛出一个叫做 KeyboardInterrupt 的异常。这就像是程序收到一个“停止”的信号。你可以捕捉到这个异常,来实现你想要的效果,比如让程序暂停,然后在5秒后继续运行:

import time

while True:
     try:
         # This is where you're doing whatever you're doing
         print("This is a line")
     except KeyboardInterrupt:
         print("Paused! Ctrl+C again within 5 seconds to kill program")
         # A second KeyboardInterrupt that happens during this sleep will
         # not be caught, so it will terminate the program
         time.sleep(5)
         print("Continuing...")

或者,你也可以让程序无限期地暂停,直到用户按下“回车”键:

while True:
     try:
         # This is where you're doing whatever you're doing
         print("This is a line")
     except KeyboardInterrupt:
         print("Interrupted!")
         input("Press enter to continue, or Ctrl+C to terminate.")
         print("Continuing...")

如果你想要捕捉第二次 KeyboardInterrupt 并做一些特别的处理,你可以通过嵌套 try/except 块来实现,不过我不太推荐这样做。因为允许连续多次的 KeyboardInterrupt 来终止程序是个更好的主意。

2

对我来说,最简单的方法是,如果我在用bash的话,可以按下Control-Z来暂停正在运行的任务,然后等我准备好了再用'fg'命令把它恢复。不过因为我不知道你用的是什么平台,所以我建议你可以先试试ChristopheD的解决方案,这可能是个不错的起点。

4

你可以试试这个在Linux / Mac(还有可能其他类Unix系统)上的实现方法(代码来源:在ActiveState代码食谱上找到的)。

如果你是在Windows上工作,可以看看msvcrt

import sys, termios, atexit
from select import select

# 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 putch(ch):
    sys.stdout.write(ch)

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

def getche():
    ch = getch()
    putch(ch)
    return ch

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

那么,实现你想要的功能就会变成这样:

atexit.register(set_normal_term)
set_curses_term()

while True:
    print "myline"
    if kbhit():
        print "paused..."
        ch = getch()
        while True
            if kbhit():
                print "unpaused..."
                ch = getch()
                break

撰写回答