来自:简讯Alfred
大家有没有觉得编程更像是这样一种行为,我们可能会用 20% 的时间将想法写入代码,然后用 80% 的时间来清除错误和修复漏洞。错误信息肯定是我们每天都会看到的,信息可能非常冗长,这样很难区分不同的部分并快速找到我们需要的信息。堆栈跟踪有时也过于复杂,难以理解。此外,除非我们覆盖异常类,否则也很难自定义错误信息,这可能又会让人不知所措。
在本文中,我将介绍一个名为 PrettyError 的库,它可以帮助我们解决上述所有痛点以及更多问题。它有许多很酷的功能,可以简化我们的调试过程,帮助我们在编码工作中节省大量时间。
像往常一样,安装 PrettyError 库非常简单。我们只需运行 pip 从 PyPI 获取即可。
pip install pretty_errors
这可能是最快捷的快速入门指南。当我们想使用默认配置的程序库时,只需在编码前导入即可。
import pretty_errors
现在,让我们定义一个不带 try-except 的函数,以便以后手动创建一些错误。
def divide(a, b):
return a / b
那么,让我们先看看没有 Pretty Errors 时的情况。我们将模拟除以零的错误。
divide(1, 0)
这就是 Python 中的原始错误信息。然后,让我们通过简单的导入来启用 Pretty Error,并再次运行代码。
import pretty_errors
divide(1, 0)
它已用颜色编码,并配有简化的指示器,如 stdin 和函数名称分隔符。
由于本文篇幅所限,无法演示颜色代码在实践中的作用。下图是 GitHub README 中的截图。
在上述场景中,您喜欢左边的(原始)还是右边的(高亮错误)?
该库能做的远不止我们在快速入门中展示的这些。在本节中,我将挑选一些关键功能进行演示。
PrettyError 允许我们自定义颜色代码。
例如,让我们在 Python 脚本文件 app.py 中输入以下代码。
import pretty_errors
open("non_existent_file.txt")
然后,让我们运行这个脚本看看会发生什么。
以上就是 PrettyError 中的默认颜色代码。如果我们想自定义代码呢?很简单,只需使用 pretty_error 模块中的 configure() 函数,如下所示。
import pretty_errors
pretty_errors.configure(
line_color = pretty_errors.BRIGHT_RED,
exception_color = pretty_errors.BRIGHT_MAGENTA,
exception_arg_color = pretty_errors.CYAN,
exception_file_color = pretty_errors.RED_BACKGROUND + pretty_errors.BRIGHT_WHITE
)
open("non_existent_file.txt")
让我们再次运行这个脚本文件。
有 16 种不同的错误信息输出类型,如 function_color、code_color 和 syntax_error_color,PrettyError 可以对它们进行自定义。
此外,你可能会注意到我使用了 PrettyError 提供的默认颜色枚举。共有 9 种不同的主色调,包括黑色、灰色、红色、绿色、黄色、蓝色、金黄色、青色和白色。每种颜色还带有前缀 BRIGHT_ 和后缀 _BACKGROUND,因此我们可以使用一系列不同的默认颜色。
除此之外,你可能会注意到我在上述配置代码中使用了组合颜色。
pretty_errors.RED_BACKGROUND + pretty_errors.BRIGHT_WHITE
这也是允许的,因此背景色和字体色可以一起用于特定的信息类型。由此可见,如果我们想自定义错误信息,PrettyError 提供了足够多的颜色代码选项。
原始 Python 错误信息的一个缺点是不能在显示错误的同时显示时间戳。当然,常见的解决方案是在程序中添加日志模块。
但是,如果程序在完全未捕获和未知异常的情况下崩溃,日志记录解决方案通常也无法实现。此外,有时我们可能出于某种原因想使用一些轻量级的解决方案。
当然,只需添加以下配置,PrettyError 就能做到这一点。
import pretty_errors
pretty_errors.configure(
display_timestamp=1
)
open("non_existent_file.txt")
配置 display_timestamp 将在显示错误的同时显示一个时间戳,如下所示。
时间戳是 perf_counter 并不完全适合人类阅读。还有一种配置可以帮助我们自定义时间戳功能。下面是一个使用 datetime 模块获取当前时间戳的示例。由于配置将函数作为参数,因此最简单的方法就是传递一个 lambda 函数。
import pretty_errors
import datetime
pretty_errors.configure(
display_timestamp=1,
timestamp_function=lambda: datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
)
open("non_existent_file.txt")
当然,如果您想要非常个性化的时间格式,最好在配置之前定义函数,然后只传递函数名。
原始 Python 错误信息的另一个限制是,它只能显示出错的代码行。在发生错误的代码之前的其他代码可能是导致错误的关键因素。除此之外,显示后面的代码也很有用,这样我们就能知道如果错误没有发生,将执行什么代码。
这可以在 PrettyError 中使用 lines_before 和 lines_after 配置来实现。
import pretty_errors
pretty_errors.configure(
lines_before=2,
lines_after=1
)
# The output shouldn't show this comment (lines before)
# The output should show this comment (lines before)
def calculate(x):
return 1 / x
# The output should show this comment (lines after)
# The output shouldn't show this comment (lines after)
def wrapper():
calculate(0)
wrapper()
请关注上述代码片段中的注释。根据配置前后的行数,我添加了一些注释,以显示错误信息中应显示哪一行代码。
我们还可以控制跟踪堆栈的级别。有时,当我们不关心主方法之前的堆栈情况时,这个功能会非常有用。因此,我们可以简化错误信息,帮助我们关注错误发生的具体位置。
这可以通过配置项 stack_depth 来实现。
import pretty_errors
pretty_errors.configure(
stack_depth=1
)
def calculate(x):
return 1 / x
def wrapper():
calculate(0)
wrapper()
因此,现在的堆栈深度更小了。
这是 Python 中最受欢迎的错误信息之一,但在原来的错误信息中却不见踪影。在开发过程中,当我们处理大多数 bug 时,经常需要使用调试工具来重现问题。
如果错误信息能告诉你变量的值是多少呢?也许在大多数情况下,我们可以直接排除故障!
在 PrettyError 中启用这一功能也非常简单,我们可以将 display_locals 配置项设置为 1。
import pretty_errors
pretty_errors.configure(
display_locals=1 # Enable the display of local variables
)
def calculate_divide(x, y):
return x / y
calculate_divide(1, 0)
让我们运行这个脚本看一看。
错误信息告诉我们这是一个 ZeroDivisionError。如果我们查看变量 x 和 y 的输出,就会发现 y 的值为 0。
实际上,我们有时可能希望错误信息非常冗长,但并非总是如此。就上文介绍的功能而言,在不同的环境中,启用或禁用这些功能的偏好也会有所不同。
因此,我们建议利用环境变量来控制 PrettyError 的行为。下面是一个例子。
import pretty_errors
import os
# Configure PrettyErrors based on the environment
if os.getenv('ENV') == 'development':
pretty_errors.configure(
stack_depth=0, # Show full stack
display_locals=1 # Show local variables in development
)
else:
pretty_errors.configure(
stack_depth=1, # Show only 3 levels depth
display_locals=0 # Hide local variables in production
)
# Main Program
def calculate(x):
return 1 / x
def wrapper():
calculate(0)
wrapper()
让我们用不同的环境变量运行脚本。请注意,如果使用的是 Windows 操作系统,则应使用 set ENV=development。当然,使用这种方法,您还可以针对不同的环境进行其他定制和配置。
在本文中,我介绍了 PrettyError。它旨在修正 Python 错误信息中存在的一些限制,确保错误信息更易于理解,从而提高开发和调试效率。它有许多有用的功能,如彩色编码、包含时间戳、显示变量值和自定义堆栈跟踪。当然,作为一种调试工具,我们可能需要考虑是否希望它在所有环境下都能工作。因此,可以引入环境变量来解决这个问题。
加入知识星球【我们谈论数据科学】
600+小伙伴一起学习!