0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何自定义Exception Hooks

Linux爱好者 来源:Python开发者 作者:南风草木香 2022-10-21 12:01 次阅读

【导语】:在日常开发的过程中,当代码报错时,我们通常要不断打印、阅读traceback提示信息,来调试代码,这篇文章介绍了如何实现一个Exception Hooks,使得traceback模块的提示信息更加精确;同时还介绍了一些第三方库,这些库也提供了Exception Hooks的功能。

简介

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

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

Exception Hooks

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

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

importsys

defexception_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}")

#Exceptiontype和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会输出如下内容:

defdo_stuff():
#写一段会产生异常的代码
raiseValueError("Someerrormessage")

do_stuff()

#Traceback:
#File/home/some/path/exception_hooks.pyline22,in
#ValueError,Message:Someerrormessage

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

defexception_hook(exc_type,exc_value,tb):

local_vars={}
whiletb:
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"Localvariablesintopframe:{local_vars}")

...

#File/home/some/path/exception_hooks.pyline41,in
#File/home/some/path/exception_hooks.pyline7,indo_stuff
#Localvariablesintopframe:{'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")

defexception_hook(exc_type,exc_value,tb):
FILE.write("***Exception:***
")
traceback.print_exc(file=FILE)

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

#***Exception:***
#NoneType:None
#
#***Traceback:***
#File"/home/some/path/exception_hooks.py",line82,in
#do_stuff()
#File"/home/some/path/exception_hooks.py",line7,indo_stuff
#raiseValueError("Someerrormessage")

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

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

defexception_hook(exc_type,exc_value,exc_traceback):
logging.critical("Uncaughtexception:",exc_info=(exc_type,exc_value,exc_traceback))


#[1733]{/home/some/path/exception_hooks.py:117}CRITICAL-Uncaughtexception:
#Traceback(mostrecentcalllast):
#File"/home/some/path/exception_hooks.py",line122,in
#do_stuff()
#File"/home/some/path/exception_hooks.py",line7,indo_stuff
#raiseValueError("Someerrormessage")
#ValueError:Someerrormessage

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

#pipinstallcolorama
fromcoloramaimportinit,Fore
init(autoreset=True)#Resetthecoloraftereveryprint

defexception_hook(exc_type,exc_value,tb):

local_vars={}
whiletb:
filename=tb.tb_frame.f_code.co_filename
name=tb.tb_frame.f_code.co_name
line_no=tb.tb_lineno
#Prependdesiredcolor(e.g.RED)toline
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}Localvariablesintopframe:{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
#pipinstallrich
#python-mrich.traceback

fromrich.tracebackimportinstall
install(show_locals=True)

do_stuff()#RaisesValueError

c74ced06-50f4-11ed-a3b6-dac502259ad0.png

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

#https://github.com/Qix-/better-exceptions
#pipinstallbetter_exceptions
#exportBETTER_EXCEPTIONS=1

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

do_stuff()#RaisesValueError

c774f5f8-50f4-11ed-a3b6-dac502259ad0.png

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

#https://github.com/onelivesleft/PrettyErrors/
#pipinstallpretty_errors

importpretty_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]

c79b00e0-50f4-11ed-a3b6-dac502259ad0.png

IPython的ultratb模块

#https://ipython.readthedocs.io/en/stable/api/generated/IPython.core.ultratb.html
#pipinstallipython
importIPython.core.ultratb

#AlsoColorTB,FormattedTB,ListTB,SyntaxTB
sys.excepthook=IPython.core.ultratb.VerboseTB(color_scheme='Linux')#Othercolors:NoColor,LightBG,Neutral

do_stuff()

c7b100ca-50f4-11ed-a3b6-dac502259ad0.png

stackprinter库

#https://github.com/cknd/stackprinter
#pipinstallstackprinter
importstackprinter
stackprinter.set_excepthook(style='darkbg2')

do_stuff()

c7c87a34-50f4-11ed-a3b6-dac502259ad0.png

结论

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

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 代码
    +关注

    关注

    30

    文章

    4741

    浏览量

    68324
  • python
    +关注

    关注

    55

    文章

    4778

    浏览量

    84439

原文标题:涨知识!Python 的异常信息还能这样展现

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    HarmonyOS开发实例:【自定义Emitter】

    使用[Emitter]实现事件的订阅和发布,使用[自定义弹窗]设置广告信息。
    的头像 发表于 04-14 11:37 969次阅读
    HarmonyOS开发实例:【<b class='flag-5'>自定义</b>Emitter】

    TP5自定义异常的处理方法

    处理器,而 set_exception_handler 可以设置用户自定义的异常处理函数:function ExceptionHandler($e) {echo "Exception
    发表于 09-20 09:05

    自定义函数测试学习工程

    自定义函数测试学习工程
    发表于 07-01 16:37 5次下载

    SOPC中自定义外设和自定义指令性能分析

    SOPC中自定义外设和自定义指令性能分析 NiosII是一个建立在FPGA上的嵌入式软核处理器,灵活性很强。作为体现NiosII灵活性精髓的两个最主要方面,自
    发表于 03-29 15:12 1598次阅读
    SOPC中<b class='flag-5'>自定义</b>外设和<b class='flag-5'>自定义</b>指令性能分析

    1602自定义字符

    1602液晶能够显示自定义字符,能够根据读者的具体情况显示自定义字符。
    发表于 01-20 15:43 1次下载

    JAVA教程之自定义光标

    JAVA教程之自定义光标,很好的学习资料。
    发表于 03-31 11:13 7次下载

    C#教程之自定义屏保

    C#教程之自定义屏保,很好的C#资料,快来学习吧。
    发表于 04-20 09:59 7次下载

    RTWconfigurationguide基于模型设计—自定义

    基于模型设计—自定义目标系统配置指南,RTW自动代码生成相关资料。
    发表于 05-17 16:41 3次下载

    PDH网管盘 自定义字节

    PDH网管盘 自定义字节
    发表于 12-26 22:13 0次下载

    如何在android设备上安装自定义rom

    完成后,请执行相同的操作,但不要选择自定义rom,而是选择间隙。安装间隙之前需要使用一些自定义rom,您可以从自定义rom的开发人员网页上了解,如果他们没有提及任何相关内容,只需在自定义
    的头像 发表于 11-05 10:48 5100次阅读

    自定义视图组件教程案例

    自定义组件 1.自定义组件-particles(粒子效果) 2.自定义组件- pulse(脉冲button效果) 3.自定义组件-progress(progress效果) 4.
    发表于 04-08 10:48 14次下载

    ArkUI如何自定义弹窗(eTS)

    自定义弹窗其实也是比较简单的,通过CustomDialogController类就可以显示自定义弹窗。
    的头像 发表于 08-31 08:24 2123次阅读

    labview自定义控件

    labview自定义精美控件
    发表于 05-15 16:46 17次下载

    自定义算子开发

    一个完整的自定义算子应用过程包括注册算子、算子实现、含自定义算子模型转换和运行含自定义op模型四个阶段。在大多数情况下,您的模型应该可以通过使用hb_mapper工具完成转换并顺利部署到地平线芯片上……
    的头像 发表于 04-07 16:11 2737次阅读
    <b class='flag-5'>自定义</b>算子开发

    labview超快自定义控件制作和普通自定义控件制作

    labview超快自定义控件制作和普通自定义控件制作
    发表于 08-21 10:32 12次下载