目录
  • 1. 引言
  • 2. 动机
  • 3. Loguru
    • 3.1 安装
    • 3.2 举个栗子
    • 3.3 使用Loguru
  • 4. Snoop
    • 4.1 安装
    • 4.2 举例
    • 4.3 使用factorial
  • 5. 总结

    1. 引言

    今天来给小伙伴推荐两款实用的便于调试Python代码的工具,可以方便展示我们调试代码的中间状态,提升大家的编码效率。

    2. 动机

    在日常工作中,经常写Python的小伙伴经常会遇到需要调试代码bug的情形,有时候我们Python的错误提示信息特别丑,

    举例如下:

    2 divided by 1 is equal to 2.0.
    Traceback (most recent call last):
    File "loguru_example.py", line 17, in <module>
    divide_numbers(num_list)
    File "loguru_example.py", line 11, in divide_numbers
    res = division(num1, num2)
    File "loguru_example.py", line 5, in division
    return num1/num2
    ZeroDivisionError: division by zero

    如果你觉得尚可接受,那我们不妨来看下如下显示错误的方式:

    分享2个方便调试Python代码的实用工具

    哇偶,没有对比就没有伤害,看了上述的显示,有木有心动。
    好滴,我们可以通过一些Python的第三方包,来实现上述调试效果。我们来看如下两款第三方Python包:

    • Loguru: 更好的打印程序异常
    • snoop: 打印函数中正在执行的代码行

    好了,接下来我们就来一个个的介绍这些好用的工具吧。

    3. Loguru

    Loguru是一个旨在使Python中的日志显示变得有趣的库。Loguru提供了许多有趣的功能,但我发现该库最有用的一个功能是捕获程序异常并显示导致代码失败的变量值。

    3.1 安装

    我们可以使用pip来直接进行安装,代码如下:

    pip install loguru

    3.2 举个栗子

    为了理解Loguru是如何工作的,假设我们现在有两个函数divisiondivide_numbers

    如下所示:

    from itertools import combinations
    def division(num1: int, num2: int):
    return num1/num2
    def divide_numbers(num_list: list):
    """Division of 2 numbers in the number list """
    for comb in combinations(num_list, 2):
    num1, num2 = comb
    res = division(num1, num2)
    print(f"{num1} divided by {num2} is equal to {res}.")
    if __name__ =='__main__':
    num_list = [2, 1, 0]
    divide_numbers(num_list)

    注意​​combinations([2,1,0], 2)​​返回值为​​[(2, 1), (2, 0), (1, 0)]​​。

    运行上述代码后,我们会出现以下错误:

    2 divided by 1 is equal to 2.0.
    Traceback (most recent call last):
    File "loguru_example.py", line 17, in <module>
    divide_numbers(num_list)
    File "loguru_example.py", line 11, in divide_numbers
    res = division(num1, num2)
    File "loguru_example.py", line 5, in division
    return num1/num2
    ZeroDivisionError: division by zero

    3.3 使用Loguru

    通过上述输出,我们知道代码行 ​​return num1/num2 ​​是错误发生的地方,但是我们并不清楚​​num1​​和​​num2​​的那些值导致的错误。幸运的是,我们可以通过添加Loguru的装饰器来捕捉此时的异常,

    代码如下:

    from loguru import logger
    from itertools import combinations
    def division(num1: int, num2: int):
    return num1/num2
    @logger.catch # Add this to track errors
    def divide_numbers(num_list: list):
    for comb in combinations(num_list, 2):
    num1, num2 = comb
    res = division(num1, num2)
    print(f"{num1} divided by {num2} is equal to {res}.")
    if __name__ =='__main__':
    num_list = [2, 1, 0]
    divide_numbers(num_list)

    运行结果如下:

    分享2个方便调试Python代码的实用工具

    通过在代码中添加logger.catch,此时的异常情况更加容易被理解!我们通过观察此时的输出,可以明确的知道当2除以0时导致函数出现异常错误信息。

    4. Snoop

    如果我们编写完的代码经过调试后没有了错误,但我们想弄清楚代码运行时发生了什么?这就是snoop派上用场的情形。

    4.1 安装

    snoop是一个第三方的Python包,通过只添加一个装饰器可以方便地打印正在执行的代码行以及每个变量的值。
    同样我们依然可以通过pip来安装snoop库,代码如下:

    pip install snoop

    4.2 举例

    假设我们有一个名为factorial的函数,它主要用于实现计算整数的阶乘。

    代码如下:

    import snoop
    def factorial(x: int):
    if x == 1:
    return 1
    else:
    return (x * factorial(x-1))
    if __name__ == "__main__":
    num = 5
    print(f"The factorial of {num} is {factorial(num)}")

    输出如下:

    The factorial of 5 is 120

     

    4.3 使用factorial

    为了理解为什么函数factorial的输出值为20,我们可以通过添加snoop的装饰器来查看函数的调用情形,

    代码如下:

    import snoop
    @snoop
    def factorial(x):
    if x == 1:
    return 1
    else:
    return (x * factorial(x-1))
    if __name__ == "__main__":
    num = 5
    print(f"The factorial of {num} is {factorial(num)}")

    输出如下:

    分享2个方便调试Python代码的实用工具

    在上述输出中,我们可以查看变量的值以及实际代码运行情形。进而通过上述输出,我们可以更好地理解递归的工作原理!

    5. 总结

    文章重点介绍了两种跟踪和可视化Python代码执行的工具。我希望通过使用这两款调试工具,来大大提升大家的工作效率和定位问题的能力。

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。