You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python类中使用curses wrapper处理未捕获异常?

解决Python curses类封装中的未捕获异常问题

问题背景

按照Python curses官方文档推荐使用wrapper自动初始化curses并处理异常,但用类封装curses功能时,类方法中出现未捕获异常会导致终端进入异常状态(需手动执行reset命令恢复),且回溯信息排版混乱。

问题代码

import curses
from curses import wrapper

class Test:
    def __init__(self, stdscr):
        self._stdscr = stdscr

    @classmethod
    def create(cls):
        _cls = wrapper(cls)
        return _cls

    def start(self):
        self._screen = curses.newpad(100, 100)
        self._screen.addstr(2, 2, 'test title', curses.A_STANDOUT)

        screen_rows, screen_cols = self._stdscr.getmaxyx()
        self._screen.refresh(0, 0, 0, 0, screen_rows - 1, screen_cols - 1)

        while True:
            self._stdscr.getch()
            1/0 # 示例未捕获异常 

t = Test.create()
t.start()

问题根源

wrapper函数的逻辑是:初始化curses环境 → 调用传入的可调用对象 → 执行finally块恢复终端。上述代码中wrapper(cls)仅负责创建Test实例,实例创建完成后wrapper就会执行endwin()恢复终端。但start()方法是在wrapper上下文之外调用的,此时调用curses API会重新进入curses模式,却没有wrapper的异常处理机制兜底,导致异常发生时终端无法自动恢复,回溯信息因curses的终端设置而排版错乱。

解决方案

方案1:让所有curses逻辑在wrapper上下文内执行

调整create类方法,让wrapper包裹一个包含实例化和启动逻辑的函数,确保所有curses操作都在wrapper的异常处理范围内:

import curses
from curses import wrapper

class Test:
    def __init__(self, stdscr):
        self._stdscr = stdscr

    @classmethod
    def create(cls):
        def run_curses(stdscr):
            instance = cls(stdscr)
            instance.start()
        wrapper(run_curses)

    def start(self):
        self._screen = curses.newpad(100, 100)
        self._screen.addstr(2, 2, 'test title', curses.A_STANDOUT)

        screen_rows, screen_cols = self._stdscr.getmaxyx()
        self._screen.refresh(0, 0, 0, 0, screen_rows - 1, screen_cols - 1)

        while True:
            self._stdscr.getch()
            1/0  # 测试未捕获异常

if __name__ == "__main__":
    Test.create()

方案2:在start方法内手动捕获异常并恢复终端

如果需要保留现有类结构,可以在start方法中捕获所有异常,先恢复终端再打印回溯信息:

import curses
from curses import wrapper
import traceback

class Test:
    def __init__(self, stdscr):
        self._stdscr = stdscr

    @classmethod
    def create(cls):
        return wrapper(cls)

    def start(self):
        try:
            self._screen = curses.newpad(100, 100)
            self._screen.addstr(2, 2, 'test title', curses.A_STANDOUT)

            screen_rows, screen_cols = self._stdscr.getmaxyx()
            self._screen.refresh(0, 0, 0, 0, screen_rows - 1, screen_cols - 1)

            while True:
                self._stdscr.getch()
                1/0  # 测试未捕获异常
        except Exception:
            # 强制恢复终端状态
            curses.endwin()
            # 正常打印异常回溯
            traceback.print_exc()

if __name__ == "__main__":
    t = Test.create()
    t.start()

效果说明

两种方案均能确保异常发生时终端自动恢复正常状态,回溯信息排版也会恢复正常,无需手动执行reset命令。

内容的提问来源于stack exchange,提问作者wasp256

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 11:43:14