网络编程
位置:首页>> 网络编程>> Python编程>> Python异常信息的不同展现方法总结

Python异常信息的不同展现方法总结

作者:爱摸鱼的菜鸟程序员  发布时间:2021-02-20 10:14:26 

标签:Python,异常,信息

简介

在日常开发中,我们的大部分时间都会花在阅读traceback模块信息以及调试代码上。本文我们将改进traceback模块,让其中的提示信息更加简洁准确。

基于这一目的,我们将会自定义Exception Hooks(异常处理钩子),用来去除traceback中的冗余信息,只留下解决报错所需的内容。此外,我还会介绍一些好用的第三方库,你可以直接使用其中的Exception Hooks,来简化traceback模块。

Exception Hooks

假如程序的异常信息没有被try/catch捕获到,python解释器就会调用sys.excepthook()函数,它会接收3个参数,分别是:type, value, traceback。这个函数也被称为Exception Hook,会输出程序的异常信息。

我们来看看下面这个例子:

import sys

def exception_hook(exc_type, exc_value, tb):
   print('Traceback:')
   filename = tb.tb_frame.f_code.co_filename
   name = tb.tb_frame.f_code.co_name
   line_no = tb.tb_lineno
   print(f"File {filename} line {line_no}, in {name}")

# Exception type 和 value
   print(f"{exc_type.__name__}, Message: {exc_value}")

sys.excepthook = exception_hook

在这个例子中,我们可以从traceback (tb)对象中获取到异常信息出现的位置,位置信息包括:文件名(f_code.co_filename),函数/模块名(f_code.co_name), 和行数(tb_lineno)。此外,我们可以使用exc_type和exc_value变量来获取异常信息的内容。

当我们调用一个会产生错误的函数时,exception_hook会输出如下内容:

def do_stuff():
   # 写一段会产生异常的代码
   raise ValueError("Some error message")

do_stuff()

# Traceback:
# File /home/some/path/exception_hooks.py line 22, in <module>
# ValueError, Message: Some error message

上述例子提供了一部分异常信息,但要想获取调试代码所需的全部信息,并知道异常出现的时间及位置,我们还需要深入研究下traceback对象:

def exception_hook(exc_type, exc_value, tb):

local_vars = {}
   while tb:
       filename = tb.tb_frame.f_code.co_filename
       name = tb.tb_frame.f_code.co_name
       line_no = tb.tb_lineno
       print(f"File {filename} line {line_no}, in {name}")

local_vars = tb.tb_frame.f_locals
       tb = tb.tb_next
   print(f"Local variables in top frame: {local_vars}")

...

# File /home/some/path/exception_hooks.py line 41, in <module>
# File /home/some/path/exception_hooks.py line 7, in do_stuff
# Local variables in top frame: {'some_var': 'data'}

由上面的例子可以看出,traceback对象(tb)本质上是一个链表 - 存储着所有出现的exceptions。因此可以使用tb_next对tb进行遍历,并打印每一个异常的信息。在此基础上,还可以使用tb_frame.f_locals属性将变量输出到console中,这有助于调试代码。

使用traceback对象输出异常信息是可行的,但是比较麻烦,此外输出的信息可读性较差。更方便的做法是使用traceback模块,该模块内置了许多提取异常信息的辅助函数。

目前我们已经介绍了Exception Hooks的基础知识,接下来我们可以自定义一个exception hooks,并加入一些实用的特性。

自定义Exception Hooks

我们还可以让异常信息自动存入文件中,在之后调试代码的时候查看:

LOG_FILE_PATH = "./some.log"
FILE = open(LOG_FILE_PATH, mode="w")

def exception_hook(exc_type, exc_value, tb):
   FILE.write("*** Exception: ***\n")
   traceback.print_exc(file=FILE)

FILE.write("\n*** Traceback: ***\n")
   traceback.print_tb(tb, file=FILE)

# *** Exception: ***
# NoneType: None
#
# *** Traceback: ***
#   File "/home/some/path/exception_hooks.py", line 82, in <module>
#     do_stuff()
#   File "/home/some/path/exception_hooks.py", line 7, in do_stuff
#     raise ValueError("Some error message")

异常信息默认会存储到stderr中,如果你想改变存储位置,可以这样做:

import logging
logging.basicConfig(
   level=logging.CRITICAL,
   format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
   datefmt='%H:%M:%S',
   stream=sys.stdout
)

def exception_hook(exc_type, exc_value, exc_traceback):
   logging.critical("Uncaught exception:", exc_info=(exc_type, exc_value, exc_traceback))
# [17:28:33] {/home/some/path/exception_hooks.py:117} CRITICAL - Uncaught exception:
# Traceback (most recent call last):
#   File "/home/some/path/exception_hooks.py", line 122, in <module>
#     do_stuff()
#   File "/home/some/path/exception_hooks.py", line 7, in do_stuff
#     raise ValueError("Some error message")
# ValueError: Some error message

我们还可以给提示信息的某一部分设置颜色:

# pip install colorama
from colorama import init, Fore
init(autoreset=True)  # Reset the color after every print

def exception_hook(exc_type, exc_value, tb):

local_vars = {}
   while tb:
       filename = tb.tb_frame.f_code.co_filename
       name = tb.tb_frame.f_code.co_name
       line_no = tb.tb_lineno
       # Prepend desired color (e.g. RED) to line
       print(f"{Fore.RED}File {filename} line {line_no}, in {name}")

local_vars = tb.tb_frame.f_locals
       tb = tb.tb_next
   print(f"{Fore.GREEN}Local variables in top frame: {local_vars}")

除了上面介绍的例子,你还可以输出每一帧的局部变量,或者找到出现异常的行中所引用的变量。这些Exception Hooks已经很成熟了,相比于自定义Exception hooks,我建议你阅读下其他开发者的源码,学习下他们的设计思路。

  • 输出每一帧的局部变量[1]

  • 找到出现异常的行中所引用的变量[2]

第三方库中的Exception Hooks

自定义一个Exception Hook很有趣,但许多第三方库已经实现这一功能了。与其自己造轮子,不如看看其他优秀的工具。

首先,我个人最喜欢的是Rich,可以直接用pip进行安装,随后导入使用。如果你只想在一个例子中使用,可以这样做:python -m rich.traceback

# https://rich.readthedocs.io/en/latest/traceback.html
# pip install rich
# python -m rich.traceback

from rich.traceback import install
install(show_locals=True)

do_stuff()  # Raises ValueError

Python异常信息的不同展现方法总结

better_exceptions也很受欢迎,我们需要先设置环境变量BETTER_EXCEPTIONS=1,再用pip安装。此外,如果你的TERM变量不是xterm,还要把SUPPORTS_COLOR设置为True。

# https://github.com/Qix-/better-exceptions
# pip install better_exceptions
# export BETTER_EXCEPTIONS=1

import better_exceptions
better_exceptions.MAX_LENGTH = None
# 检查你的 TERM 变量是否被设置为 `xterm`, 如果没有执行以下操作
# See issue: https://github.com/Qix-/better-exceptions/issues/8
better_exceptions.SUPPORTS_COLOR = True
better_exceptions.hook()

do_stuff()  # Raises ValueError

Python异常信息的不同展现方法总结

使用最方便的库是pretty_errors,只需导入即可:

# https://github.com/onelivesleft/PrettyErrors/
# pip install pretty_errors

import pretty_errors
# 如果你对默认配置满意的话,则无需修改
pretty_errors.configure(
   filename_display    = pretty_errors.FILENAME_EXTENDED,
   line_number_first   = True,
   display_link        = True,
   line_color          = pretty_errors.RED + '> ' + pretty_errors.default_config.line_color,
   code_color          = '  ' + pretty_errors.default_config.line_color,
   truncate_code       = True,
   display_locals      = True
)

do_stuff()

除了直接导入外,上面的代码还显示了该库的一些可选配置。更多的配置可以查看这里:配置[3]

Python异常信息的不同展现方法总结

IPython的ultratb模块

# https://ipython.readthedocs.io/en/stable/api/generated/IPython.core.ultratb.html
# pip install ipython
import IPython.core.ultratb

# Also ColorTB, FormattedTB, ListTB, SyntaxTB
sys.excepthook = IPython.core.ultratb.VerboseTB(color_scheme='Linux')  # Other colors: NoColor, LightBG, Neutral

do_stuff()

Python异常信息的不同展现方法总结

stackprinter库

# https://github.com/cknd/stackprinter
# pip install stackprinter
import stackprinter
stackprinter.set_excepthook(style='darkbg2')

do_stuff()

Python异常信息的不同展现方法总结

结论

本文我们学习了如何自定义Exception Hooks,但我更推荐使用第三方库。你可以在本文介绍的第三方库中任选一个喜欢的,用到项目中。需要注意的是使用自定义Exception Hooks可能会丢失某些关键信息,例如:本文中的某些例子中,输出中缺少文件路径,在远程调试代码这无疑很不方便,因此,需要谨慎使用。

来源:https://blog.csdn.net/weixin_56659172/article/details/127998909

0
投稿

猜你喜欢

  • 1. 介绍 SQLite 是一个开源的嵌入式关系数据库,实现自包容、零配置、支持事务的SQL数据库引擎。 其特点是高度便携、使用方便、结构紧
  • 0. 前言无论在工作中,还是学习中,都会出现这样子的需求,对某张表进行了排序(按时间排序也好,其他字段排序也罢),然后获取前x行的数据,由于
  • 什么是特殊方法?当我们在设计一个类的时候,python中有一个用于初始化的方法$__init__$,类似于java中的构造器,这个就是特殊方
  • 本文实例为大家分享了python sort、sort_index的具体代码,供大家参考,具体内容如下对Series进行排序#生成序列objo
  • 内容摘要:在网页制作中,有许多的术语,例如:CSS、HTML、DHTML、XHTML等等。在下面的文章中我们将会用到一些有关于HTML的基本
  • 前言在两种python循环语句的使用中,不仅仅是循环条件达到才能跳出循环体。所以,在对python函数进行阐述之前,先对跳出循环的简单语句块
  • 被Scrapy自动添加的头部在没有任何配置的情况下,scrapy会对请求默认加上一些头部信息Scrapy会通过配置文件中的USER_AGEN
  • asp之家注:有时候我们想让程序运行变慢下来,asp中该怎么做呢?原理很简单就是在运行程序前运行一段无关紧要的程序就可以了,要实现加长程序的
  • 准备篇:1、配置防火墙,开启80端口、3306端口说明:Ubuntu默认安装是没有开启任何防火墙的,为了服务器的安全,建议大家安装启用防火墙
  • 使用access数据库时可能用到的数据转换:类型转换涵数:函数 返回类型 expression 参数范围CBool Boolean 任何有效
  • 做项目的时候,一位同事导数据的时候,不小心把一个表中的数据全都搞重了,也就是说,这个表里所有的记录都有一条重复的。这个表的数据是千万级的,而
  • 前言:为了帮助广大考生和家长了解高考历年的录取情况,很多网站都汇总了各省市的录取控制分数线,为广大考生填报志愿提供参考。因受多种因素影响,每
  • 本文实例为大家分享了python版百度语音识别功能的具体代码,供大家参考,具体内容如下环境:使用的IDE是Pycharm1.新建工程2.配置
  • 最近自己很关注文档的撰写,包括如何制作PPT。因为发现自己在表达想法和观点的时候,从自己的语言到文字都异常的欠缺。常常需要“高人”帮忙翻译。
  • MySQL GUI工具很多,本文就常用的Navicat for MySQL与MySQL-Front的特色功能做一个详细介绍与比较。(一)My
  • pcntl扩展可以支持php的多线程操作(仅限linux)原本需要重新编译PHP的后面configrue提示加上--enable-pcntl
  • 本文实例讲述了php实现mysql事务处理的方法。分享给大家供大家参考。具体分析如下:要实现本功能的条件是环境 mysql 5.2 /php
  • 在查看Mysql对文件的操作中,它在不同的操作系统上对文件的操作,除了使用标准C运行库函数,包括open、close、seek等,在Win3
  • 由于代码比较短,这里就不进行注释了代码如下:<% '当目标页面的包含文件即#include的页面里边存在respon
  • 前言这篇文章主要介绍了Python 字符串去除空格的6种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,来
手机版 网络编程 asp之家 www.aspxhome.com