sys.excepthook' 与线程处理

27 投票
3 回答
13407 浏览
提问于 2025-04-15 15:29

我正在使用Python 2.5,并尝试在我的程序中使用自己定义的excepthook。在主线程中,它工作得很好。但是在使用线程模块启动的线程中,通常的excepthook会被调用。

这里有一个例子展示了这个问题。取消注释后就能看到想要的效果。

import threading, sys

def myexcepthook(type, value, tb):
    print 'myexcepthook'

class A(threading.Thread, object):

    def __init__(self):
        threading.Thread.__init__(self, verbose=True)
#       raise Exception('in main')
        self.start()

    def run(self):
        print 'A'
        raise Exception('in thread')            

if __name__ == "__main__":
    sys.excepthook = myexcepthook
    A()

那么,我该如何在一个线程中使用我自己的excepthook呢?

3 个回答

13

看起来这里有一个相关的错误报告,详细内容可以在这里找到,里面还有一些解决方法。建议的做法基本上是在运行代码时加上一个“尝试/捕获”的结构,然后调用 sys.excepthook(*sys.exc_info()) 来处理错误。

23

看起来这个问题在(至少)3.4版本中仍然存在,而Nadia Alramli提到的讨论中的一个解决方法在Python 3.4中似乎也有效。

为了方便大家和记录下来,我在这里分享我认为最好的解决方法的代码。我稍微更新了一下代码风格和注释,使其更符合PEP8标准和Python的风格。

import sys
import threading

def setup_thread_excepthook():
    """
    Workaround for `sys.excepthook` thread bug from:
    http://bugs.python.org/issue1230540

    Call once from the main thread before creating any threads.
    """

    init_original = threading.Thread.__init__

    def init(self, *args, **kwargs):

        init_original(self, *args, **kwargs)
        run_original = self.run

        def run_with_except_hook(*args2, **kwargs2):
            try:
                run_original(*args2, **kwargs2)
            except Exception:
                sys.excepthook(*sys.exc_info())

        self.run = run_with_except_hook

    threading.Thread.__init__ = init
29

我刚遇到这个问题,结果发现这正是个好时机。

在3.8版本中新增了: threading.excepthook

这个功能用来处理线程运行时出现的未捕获异常。

它的参数有以下几个属性:

exc_type: 异常的类型。
exc_value: 异常的值,可以是None。
exc_traceback: 异常的追踪信息,可以是None。
thread: 抛出异常的线程,可以是None。

我不知道为什么,但要注意,和 sys.excepthook 不同的是, threading.excepthook 接收的参数是以 namedtuple 的形式,而不是多个单独的参数。

撰写回答