最简单的方法是更改sys.excepthook
函数:
import sys
def my_hook(exc_type, exc_value, exc_tb):
sys.stderr.write('{}: {}\n'.format(exc_type.__name__, exc_value))
sys.stderr.flush()
sys.exit(-1)
sys.excepthook = my_hook
在此更改之后,每当引发未捕获的异常时,将不会打印回溯并且程序将退出:
>>> raise RuntimeError('ARGHHH!!!')
RuntimeError: ARGHHH!!!
如果要替换sys.stderr
以执行此操作,则必须检查是否正在打印回溯。例如:
class NastyStderr(object):
def __init__(self, stream):
self.stream = stream
self.printing_traceback = False
def write(self, data):
if self.printing_traceback:
if not data.startswith(' '):
self.stream.write(data)
self.stream.flush()
self.printing_traceback = False
else:
if data.startswith('Traceback'):
self.printing_traceback = True
elif not data.startswith('\nDuring handling'):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
用作:
>>> sys.stderr = NastyStderr(sys.stderr)
>>> raise ValueError('A')
ValueError: A
>>> try:
... raise RuntimeError('A')
... except Exception as e:
... raise ValueError('B')
...
RuntimeError: A
ValueError: B
正如您在第二个示例中看到的那样,它会打印发生的两个异常。编写一个NastyStderr
能够理解它应该只打印第二个的将是相当困难的。
但是,更改sys.excepthook
解决方案以在回溯中打印所有异常非常简单:
>>> import sys
>>> def my_hook(exc_type, exc_value, exc_tb, exit=True):
... if exc_value.__context__ is not None:
... prev = exc_value.__context__
... my_hook(prev.__class__, prev, prev.__traceback__, exit=False)
... sys.stderr.write('{}: {}\n'.format(exc_type.__name__, exc_value))
... sys.stderr.flush()
... if exit:
... sys.exit(-1)
...
>>> sys.excepthook = my_hook
>>> try:
... raise Exception('A')
... except Exception:
... raise ValueError('B')
...
Exception: A
ValueError: B