'sys.excepthook'和线程技术

27

我正在使用 Python 2.5 并尝试在程序中使用自定义的 excepthook。在主线程中,它完美地工作。但在使用 threading 模块启动的线程中,通常的 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个回答

28

我刚刚发现这个问题,结果证明这是一个及时发现的时机。

版本3.8中的新功能:threading.excepthook

处理由Thread.run()引发的未捕获异常。

args参数具有以下属性:

exc_type:异常类型。
exc_value:异常值,可以为None。
exc_traceback:异常回溯,可以为None。
thread:引发异常的线程,可以为None。

我不知道为什么,但要注意,与sys.excepthook不同,threading.excepthook将参数作为namedtuple接收,而不是多个参数。


4
如果你想让主线程之外的异常也被处理,那么简单的技巧是同时设置threading.excepthooksys.excepthook。这个答案现在应该得到更高的评价。 - Nilan Saha
感谢您的“注意事项”提醒。这个事实很容易被忽视。 - undefined

23

看起来这个错误在(至少)3.4版本中仍然存在,并且Nadia Alramli链接讨论中的一个解决方法也似乎适用于Python 3.4。

为了方便和文档记录,我会在这里发布(在我看来)最好的解决方法的代码。我稍微更新了编码风格和注释,使其更符合PEP8和Pythonic。

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

我希望这个回答被采纳。看起来从来没有一个答案。请随意将其放在 https://dev59.com/9lUL5IYBdhLWcg3w4rWQ,我会将其标记为答案。 - Travis Griggs
1
@TravisGriggs Stack Overflow 不会喜欢这个,因为他们不喜欢重复的内容。但你可以回答自己的问题并引用这个问题,然后接受它作为答案。 - gitaarik
3
Python 3.8版本已经修复了这个漏洞。 - max

13

看起来已经有一个相关的错误报告在这里,提供了解决办法。建议使用的技巧基本上是在try/catch中包装运行,然后调用sys.excepthook(*sys.exc_info())


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接