我正在玩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),它都不会弄乱终端?
答案 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)
你可以:
对于基本情况,第一个选项可能是最简单的(如果你没有运行很多代码)。
第二个选项是最具体的,如果你想为Ctrl + C做一些特殊。
如果您总是希望执行某些关闭操作,那么最后一个选项是最强大的,无论您的程序如何结束。
答案 4 :(得分:-1)
您需要捕获信号并在捕获过程中运行endwin()
。
有关此问题的信息,请查看此SO答案:How do I capture SIGINT in Python?