背景
通常使用traceback.format_exc()捕捉异常,其会把异常的堆栈信息打印出来形成字符串返回,但是有时候返回信息过多,所以就想了解一下用法。
参数说明
format_exc(limit=None, chain=True) limit:打印最后的 abs(limit) 条目 chain:如果chain为true(默认值),则也将打印链接异常(异常的 _cause_ 或 _context_ 属性),就像解释器本身在打印未处理的异常时所做的那样
test.py
import traceback
import requests
def f():
try:
requests.get('http://1.1.1.1', timeout=0.1)
except:
print(traceback.format_exc(limit=2, chain=False))
if __name__ == '__main__':
print(123)
f()
print(456)
输出:
123
Traceback (most recent call last):
File "D:/software/work/code/test/traceback_test.py", line 13, in f
requests.get('http://1.1.1.1', timeout=0.1)
File "D:\software\work\code\test\venv\lib\site-packages\requests\api.py", line 72, in get
return request('get', url, params=params, **kwargs)
requests.exceptions.ConnectTimeout: HTTPConnectionPool(host='1.1.1.1', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x00000216B10256A0>, 'Connection to 1.1.1.1 timed out. (connect timeout=0.1)'))
456
test2.py
import traceback
import requests
def f():
try:
requests.get('http://1.1.1.1', timeout=0.1)
except:
print(traceback.format_exc(limit=1, chain=False))
if __name__ == '__main__':
print(123)
f()
print(456)
输出
123
Traceback (most recent call last):
File "D:/software/work/code/test/traceback_test.py", line 13, in f
requests.get('http://1.1.1.1', timeout=0.1)
requests.exceptions.ConnectTimeout: HTTPConnectionPool(host='1.1.1.1', port=80): Max retries exceeded with url: / (Caused by ConnectTimeoutError(<urllib3.connection.HTTPConnection object at 0x0000012A61875630>, 'Connection to 1.1.1.1 timed out. (connect timeout=0.1)'))
456
获取线程中的异常信息
通常情况下我们无法将多线程中的异常带回主线程,所以也就无法打印线程中的异常,而通过上边学到这些知识,我们可以对线程做如下修改,从而实现捕获线程异常的目的。
import threading
import traceback
def my_func():
raise BaseException("thread exception")
class ExceptionThread(threading.Thread):
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, verbose=None):
"""
Redirect exceptions of thread to an exception handler.
"""
threading.Thread.__init__(self, group, target, name, args, kwargs, verbose)
if kwargs is None:
kwargs = {}
self._target = target
self._args = args
self._kwargs = kwargs
self._exc = None
def run(self):
try:
if self._target:
self._target()
except BaseException as e:
import sys
self._exc = sys.exc_info()
finally:
#Avoid a refcycle if the thread is running a function with
#an argument that has a member that points to the thread.
del self._target, self._args, self._kwargs
def join(self):
threading.Thread.join(self)
if self._exc:
msg = "Thread '%s' threw an exception: %s" % (self.getName(), self._exc[1])
new_exc = Exception(msg)
raise new_exc.__class__, new_exc, self._exc[2]
t = ExceptionThread(target=my_func, name='my_thread')
t.start()
try:
t.join()
except:
traceback.print_exc()
输出:
Traceback (most recent call last):
File "/data/code/testcode/thread_exc.py", line 43, in <module>
t.join()
File "/data/code/testcode/thread_exc.py", line 23, in run
self._target()
File "/data/code/testcode/thread_exc.py", line 5, in my_func
raise BaseException("thread exception")
Exception: Thread 'my_thread' threw an exception: thread exception
参考链接
https://www.docs4dev.com/docs/zh/python/3.7.2rc1/all/library-traceback.html