内部诅咒时如何引发KeyboardInterrupt

时间:2014-01-14 20:17:52

标签: python python-2.7 curses pdcurses

在Windows上使用curses模块(via this PDCurses),我试图打破KeyboardInterrupt异常,但是当我按ctrl + c时它不会升起。

一些提炼代码:

from curses import wrapper
items = ['a', 'very', 'long', 'list', 'of', 'strings']

def main(screen):
    for item in items:
        screen.addstr(0, 0, item)
        screen.getch()
        screen.refresh()

wrapper(main)

items列表很长,现在我无法停止执行。我必须反复按键直到我结束。天堂禁止我曾在while True:中试过这个!

按ctrl + c时,不会引发异常。它确实传递给我的getch() 3。在getch收到3时是否手动提高SOP,或者是否有更合适的方法可以避免吞咽KeyboardInterrupt

3 个答案:

答案 0 :(得分:2)

默认curses使用raw模式,从文档中关闭中断/退出/暂停等

  

在原始模式下,正常行缓冲和处理中断,退出,   暂停,流量控制键关闭;人物是   呈现给逐个诅咒输入函数

来自C的诅咒documentation

  

这两个函数(rawcbreak)之间的区别在于   控制字符的方式如挂起(CTRL-Z),中断和退出   (CTRL-C)传递给程序。 raw()模式下这些   字符直接传递给程序而不生成   信号。

由于python在发送KeyboardInterrupt时会引发SIGINT,因此预计不会引发它3。您看到getch 表示中断。

由于这是C库处理的事情,因此无法避免异常的“吞咽”。但是,您可以使用3的简单包装器检查何时返回{{1}}并相应地引发错误。

答案 1 :(得分:0)

使用UGETCHAR_(如下实现)代替getch

def UGETCHAR_(scr):
    import curses
    h = scr.getch()
    if h == 3:
        raise KeyboardInterrupt
    if h == 26:
        raise EOFError
    return h

让我解释一下。

因此,首先调用该函数时,它将导入curses [import curses]。

接下来,它将运行您正在使用的getch()并将结果放入名为h的变量中。 [h = scr.getch()]

然后,如果raise KeyboardInterrupt为3(h [^C],则引发KeyboardInterrupt [if h == 3:];如果{{1,则引发EOFError [raise KeyboardInterrupt] }}是26(h)[^Z]。

最后,它返回if h == 26: [h]的值。

答案 2 :(得分:0)

很久以前就有人问过这个问题,但我遇到了完全相同的问题。我想要一个使用 curses 的 Python 程序在 Windows 和 Linux 上运行。 KeyboardInterrupt 在 Linux 上完全按预期工作,但在 Windows 上则不然。我尝试了所有的 curses 设置功能,但始终无法使用 Ctrl+C 来中断执行。

下面的代码似乎有效,但并不理想。到目前为止我找不到更好的方法。这种方法在 Windows 上的问题在于它不会中断。在检查输入之前,代码将完成它在当前循环迭代中所做的任何工作。 (它在 Linux 上仍然可以完美运行。)

import curses
import time

def Main(stdscr):
    stdscr.addstr(0, 0, "Main starting.  Ctrl+C to exit.")
    stdscr.refresh()
    try:
        i = 0
        while True:
            i = i + 1
            stdscr.addstr(1, 0, "Do work in loop. i=" + str(i))
            stdscr.refresh()
            time.sleep(1)

            stdscr.nodelay(1) # Don't block waiting for input.
            c = stdscr.getch() # Get char from input.  If none is available, will return -1.
            if c == 3:
                stdscr.addstr(2, 0, "getch() got Ctrl+C")
                stdscr.refresh()
                raise KeyboardInterrupt
            else:
                curses.flushinp() # Clear out buffer.  We only care about Ctrl+C.
        
    except KeyboardInterrupt:
        stdscr.addstr(3, 0, "Ctrl+C detected, Program Stopping")
        stdscr.refresh()
    
    finally:
        stdscr.addstr(4, 0, "Program cleanup")
        stdscr.refresh()
        time.sleep(3) # This delay just so we can see final screen output

curses.wrapper(Main)

Linux 上的输出:

Main starting.  Ctrl+C to exit.
Do work in loop. i=4

Ctrl+C detected, Program Stopping
Program cleanup

Windows 上的输出:

Main starting.  Ctrl+C to exit.
Do work in loop. i=6
getch() got Ctrl+C
Ctrl+C detected, Program Stopping
Program cleanup