Python诅咒困境

时间:2012-03-24 18:51:21

标签: python ncurses curses

我正在玩Python和诅咒。

当我跑步时

import time
import curses

def main():
    curses.initscr()
    curses.cbreak()
    for i in range(3):
        time.sleep(1)
        curses.flash()
        pass
    print( "Hello World" )
    curses.endwin()

if __name__ == '__main__':
    main()

如果我一直等待,curses.endwin()被调用,所以一切正常。 但是,如果我用Ctrl-C缩短它,curses.endwin()永远不会被调用,所以它会搞砸我的终端会话。

处理这种情况的正确方法是什么?我如何确保无论我如何尝试结束/中断程序(例如Ctrl-C,Ctrl-Z),它都不会弄乱终端?

5 个答案:

答案 0 :(得分:47)

我相信你正在寻找curses.wrapper 见http://docs.python.org/dev/library/curses.html#curses.wrapper

它将在init上执行curses.cbreak(),curses.noecho()和curses_screen.keypad(1)并在退出时将其反转,即使退出是异常。

您的程序作为包装器的函数,例如:

def main(screen):
    """screen is a curses screen passed from the wrapper"""
    ...

if __name__ == '__main__':
    curses.wrapper(main)

答案 1 :(得分:8)

你可以这样做:

def main():
    curses.initscr()

    try:
        curses.cbreak()
        for i in range(3):
            time.sleep(1)
            curses.flash()
            pass
        print( "Hello World" )
    finally:
        curses.endwin()

或者更好的是,制作一个上下文包装器:

class CursesWindow(object):
    def __enter__(self):
        curses.initscr()

    def __exit__(self):
        curses.endwin()

def main():
    with CursesWindow():
        curses.cbreak()
        for i in range(3):
            time.sleep(1)
            curses.flash()
            pass
        print( "Hello World" )

答案 2 :(得分:1)

我的建议:出于测试目的,使用简单的包装器shell脚本调用脚本;让shell脚本执行reset命令,使终端设置恢复到可用状态:

#!/bin/sh
eval "$@"
stty -sane
reset

...将其称为run.sh并感到高兴。如果你将参数作为命令输入,那么这应该像你的shell一样运行你的命令(更确切地说,如果你用硬引号包装参数)。

为了确保您的程序能够使终端处于健壮状态,面对未捕获的异常和异常终止...要么使用curses.wrapper()方法调用您的顶级入口点(可能是{{ 1}}或者你选择实现的main()或者用你自己的main_curses_ui()方法序列包装代码来恢复光标可见性,恢复“cbreak”(规范/熟入输入)模式,恢复正常“回声”设置以及你可能已经使用过的任何其他内容。

您还可以使用Python: atexit Handlers注册所有清理操作。但是可能仍然存在不会调用代码的情况 - 某些非捕获信号以及调用 os._exit()的任何情况。

即使在这些情况下,我的小shell脚本包装器也应该非常强大。

答案 3 :(得分:0)

你可以:

  • 将您的代码包装在调用try的{​​{1}} / finally块中
  • 专门通过signal
  • 捕获中断信号
  • 使用atexit库。

对于基本情况,第一个选项可能是最简单的(如果你没有运行很多代码)。

第二个选项是最具体的,如果你想为Ctrl + C做一些特殊

如果您总是希望执行某些关闭操作,那么最后一个选项是最强大的,无论您的程序如何结束。

答案 4 :(得分:-1)

您需要捕获信号并在捕获过程中运行endwin()

有关此问题的信息,请查看此SO答案:How do I capture SIGINT in Python?