Python curses dilemma
我正在玩Python和诅咒。
我跑的时候
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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() |
如果我一直等待,
但是,如果我用Ctrl-C缩短它,
处理这种情况的正确方法是什么? 我怎样才能确保无论我如何尝试结束/中断程序(例如Ctrl-C,Ctrl-Z),它都不会弄乱终端?
我相信你正在寻找curses.wrapper
请参阅http://docs.python.org/dev/library/curses.html#curses.wrapper
它将在init上执行curses.cbreak(),curses.noecho()和curses_screen.keypad(1)并在退出时反转它们,即使退出是异常。
您的程序作为包装器的函数,例如:
1 2 3 4 5 6 | def main(screen): """screen is a curses screen passed from the wrapper""" ... if __name__ == '__main__': curses.wrapper(main) |
你可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 | def main(): curses.initscr() try: curses.cbreak() for i in range(3): time.sleep(1) curses.flash() pass print("Hello World" ) finally: curses.endwin() |
或者更好的是,创建一个上下文包装器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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" ) |
我的建议:出于测试目的,使用简单的包装器shell脚本调用脚本;让shell脚本执行
1 2 3 4 | #!/bin/sh eval"$@" stty -sane reset |
...称之为
为了确保你的程序能够使终端处于健壮状态,面对未捕获的异常和异常终止......要么使用
您还可以使用Python:atexit Handlers来注册所有清理操作。但是可能仍然存在无法调用代码的情况---某些非捕获信号以及调用os._exit()的任何情况。
即使在这些情况下,我的小shell脚本包装器也应该相当强大。
您可以:
-
将代码包装在调用
curses.endwin() 的try /finally 块中 -
通过
signal 库专门捕获中断信号 -
使用
atexit 库。
对于基本情况,第一个选项可能是最简单的(如果你没有运行很多代码)。
第二个选项是最具体的,如果你想为Ctrl + C做一些特殊的事情。
如果您总是希望执行某些关闭操作,那么最后一个选项是最强大的,无论您的程序如何结束。
您需要捕获信号并在捕获期间运行
有关这方面的信息,请看这个答案:如何在Python中捕获SIGINT?