python 随时终止程序?

3 投票
5 回答
4606 浏览
提问于 2025-04-18 18:36

我希望能在运行程序的任何时候结束它。就像我按下 ctrl + c 时,程序会显示“键盘中断”,但我不想要那种方式。

if "keyboard press here" == true:
  quit()

我不想要那种方式的原因是,因为我的代码会一直运行,直到它到达代码中的某个部分。有没有什么命令可以做到这一点呢?

补充说明:

抱歉,如果我没有清楚表达我的问题。我的意思是,我不想让我的程序必须运行到“按键退出”的那一行才可以结束,而是希望在每个地方都能做到。例如,如果我有一个看起来像这样的循环:

while True
print "1"
print "2"
if "keyboard press here" == true:
      quit()
print "3"
print "4"

我必须等到它打印出

>>>1
>>>2

之前才能按键停止,或者如果它打印到 2 后又继续打印 3,那样看起来会是这样:

>>>1
>>>2
>>>3
>>>4
>>>1
>>>2

然后我的程序才会停止。

我希望我的程序能像这样工作:

while True
    print "1"
    if "keyboard press here" == true:
          quit()
    print "2"
    if "keyboard press here" == true:
          quit()
    print "3"
    if "keyboard press here" == true:
          quit()
    print "4"
    if "keyboard press here" == true:
          quit()

但我不想在每个地方都重复写

if "keyboard press here" == true: quit()

。有没有办法做到这一点呢?

5 个回答

0

我觉得你想要的效果是让你的程序在每一步都停下来,问你是否要继续?

有一种比较简单的方法可以实现这个效果,那就是在Python的调试工具pdb中运行你的程序。在程序的开头或者循环的第一行设置一个断点:

import pdb
pdb.set_trace()

然后,当你执行程序时,就会进入pdb的提示符。在每一步,你可以输入'next'或者'n'来继续。如果你想退出调试器,让程序自然结束,可以输入'c'(代表'继续')。如果你想退出调试器,可以按ctrl+D。

如果这个程序只是你自己用,那这样做会很方便。如果你打算把它分享给别人,那就不太合适了。

0

根据我的理解,你想要用一种不同的按键组合来结束你的程序,类似于按下 ctrl-c 的效果。实现这个目标的一种方法是把读取输入的部分放到一个单独的线程中,然后让这个线程自己结束程序。主线程可以捕捉到 KeyboardInterrupt 这个事件,这样在程序结束时就不会出现 Python 的错误堆栈信息了。

import os
import sys
import threading
import time
import signal

def kill_handler():
    data = sys.stdin.read(1)
    os.kill(os.getpid(), signal.SIGINT)

def main():
    kill_thread = threading.Thread(target=kill_handler)
    kill_thread.daemon = True
    kill_thread.start()

    print "press enter to terminate"
    try:
        while True:
            print 1
            time.sleep(.5)
            print 2
            time.sleep(.5)
            print 3
            time.sleep(.5)
            print 4
            time.sleep(.5)
    except KeyboardInterrupt:
        print "terminating"

if __name__=='__main__':
    main()
0

要实现你想要的功能,你的代码需要在一个无限循环中运行。这个做法是否合适,取决于你正在编写的程序类型。

假设这段代码在一个无限循环中运行,并且没有任何会让它变慢的暂停时间,你只需要按照你上面写的方式去做。

你说得对,程序必须执行到那个点,语句才能生效。但由于你在一个运行得非常快的无限循环中,用户感觉到的时间几乎是瞬间的。

补充:根据循环的大小以及你的程序是否会有较长时间的暂停,你可能需要在循环的多个地方放置条件判断。

(通常是在循环的开头放一次,然后在每次暂停后再放一次)

根据评论1和评论2进一步编辑:
在你的情况下,我会这样做:

 flag=False
 while True:
      if flag:
         quit() # or break or whatever you want to do

      print 1
      print 2
      #press to continue function to prompt and get key press/ set variable goes here....
      if pressed:
         flag=True
         continue
      print 3 
      print 4
      .....

告诉程序“继续”会让它立即开始下一次循环,但因为你设置了标志,程序就不会运行。

不过,我不太确定我完全理解你想要的,因为按照这个逻辑,你可以简单地写:

if pressed:
   sys.exit()

我现在明白你想要什么了,你只需要像Sebastian说的那样用异常来处理中断,或者像其他人建议的那样使用信号处理器

2

你可以创建一个信号处理器,或者用你自己的异常处理函数来覆盖默认的。

信号处理器

信号处理器可能会有帮助。

import sys
import signal


def terminate(signal, frame):
    print("received SIGINT, exit..." file=sys.stderr)
    sys.exit(0)

signal.signal(signal.SIGINT, terminate)

for i in range(0, 100000):
    print(i)

不过,使用信号处理器时要非常小心,你需要非常仔细地编写它。 即使是经验丰富的UNIX C程序员,写一个正确的信号处理器也很难。

当一个程序接收到信号时,它会被强行暂停。

比如说,print()在工作时会占用一个流或输入输出设备,当信号产生时,它会暂停,以便执行信号处理器。这时候,如果当前的print()还没有返回,你就不能再调用(可重入的)print(),因为它还在占用那个流/设备。

更糟糕的是,当当前的信号处理器还在运行时,信号可能会被触发。所以,信号处理器和所有的函数都必须允许可重入调用。

不过在Python中,这个问题相对简单和安全,因为Python已经做了必要的工作,允许核心函数进行可重入调用。

异常处理钩子

追踪错误是从哪里来的呢?当出现未处理的异常时,Python会调用一个特殊的函数(sys.__excepthook__)来打印追踪信息。

你可以覆盖这个函数,做一些额外的事情(除了引发未处理的异常以避免无限递归 ^_^),而且你不需要担心可重入的问题。

我们通常使用这个功能将错误记录到日志文件中,或者弹出一个警告窗口。但这也适用于你的情况。

import sys


def my_excepthook(type, value, traceback):
    if type is KeyboardInterrupt:
        print("got KeyboardInterrupt, exit...")
        sys.exit(0)
    else:
        # call the original hook to print the trackback properly
        sys.__excepthook__(type, value, traceback)

sys.excepthook = my_excepthook

for i in range(0, 100000):
    print(i)

顺便提一下,提醒一下,这两种方法适用于多线程编程,但你需要做的事情比示例中更多,而且要更加小心。

3

嗯,这个方法看起来不太好,但我能想到的就是处理键盘中断...

while True:
    try:
        # your main code here   
    except KeyboardInterrupt:
        break # or quit(), or sys.exit()

编辑:

来回答你更新后的问题:

我的意思是,我不想等到程序运行到“按键盘退出”这一步,而是希望在每个地方都能处理这个情况。

其实你不需要这样,try-except 就能做到你想要的效果。要把这段代码应用到你更新后的问题上:

while True:
    try:
        print "1"
        print "2"
        print "3"
        print "4"
    except KeyboardInterrupt:
        break

撰写回答