写点什么

扔掉 print,用 icecream 来调试你的代码

  • 2024-03-25
    福建
  • 本文字数:2479 字

    阅读完需:约 8 分钟

print是我们平时写些python小工具时,最常用的调试工具。因为开发代码时,常常通过print将执行流程、变量的值以及其他关键信息输出到控制台来观察,以便了解程序执行情况和调试bug

但是,print的输出过于简单,在输出变量内容,函数调用,执行过程等相关信息时,往往需要自己手动去补充很多的输出信息的说明,否则很容易搞不清输出的内容是什么。

而今天介绍的icecream,为我们提供了一种更加优雅和强大的方式来调试代码。它不仅可以自动格式化输出内容,自动添加必要的描述信息,而且使用起来也比print更加简单。


1. 安装


通过pip安装:

pip install icecream
复制代码


安装之后可以通过打印其版本来验证是否安装成功。



2. 使用示例


下面看看icecream如何替换开发中常见的各种print场景。


2.1. 调试变量


首先是调试变量,这也是用的最多的场景。开发中,我们常常需要将变量打印出来以确认是否正确赋值。

print方式:

# 数值和字符串i = 100f = 3.14s = "abc"print(i, f, s)
# 元组,列表和字典t = (10, 20, 30)l = [1, 2, 3]d = {"A": "abc", "B": 100}print(t, l, d)print(t[0], l[1], d["A"])
# 类class c: name = "ccc" addr = "aa bb cc"
print(c.name, c.addr)
复制代码



icecream方式:

from icecream import ic
# 数值和字符串i = 100f = 3.14s = "abc"ic(i, f, s)
# 元组,列表和字典t = (10, 20, 30)l = [1, 2, 3]d = {"A": "abc", "B": 100}ic(t, l, d)ic(t[0], l[1], d["A"])
# 类class c: name = "ccc" addr = "aa bb cc"
ic(c.name, c.addr)
复制代码



通过比较,可以看出icecream的几个优势:

  1. 输入效率更高,因为icprint更容易输入,只有两个字母。

  2. 自动带上变量名称,一眼看出打印的是哪个变量的值

  3. 变量名称和值用不同的颜色显示,容易区分


2.2. 调试函数输出


调试函数输出也是常用的,如果把函数调用也看做一个变量的话,其实这个和上面打印变量类似。print方式:

def func(a: int, b: int):    return a + b
print(func(2, 3))
复制代码



icecream方式:

from icecream import ic
def func(a: int, b: int): return a + b
ic(func(2, 3))
复制代码



2.3. 调试执行过程


接下来是调试执行过程,当代码中有很多分支判断时,我们常常是在各个分支中print不同的数字,然后用不同的输入看看代码是否按照预期的那样进入不同而分支。比如,下面构造一个多分支判断的函数,看看分别用printicecream是如何调试的。

print方式:

def pflow(a: float, b: float):    print(1)    evaluate = ""    if a > 90 and b > 90:        print(2)        evaluate = "优"    elif a > 80 and b > 80:        print(3)        evaluate = "良"    elif a > 70 and b > 70:        print(4)        evaluate = "中"    else:        print(5)        evaluate = "及格"
if a < 60 or b < 60: print(6) evaluate = "不合格"
print(7) return evaluate
pflow(98, 92)print("---------------------")pflow(75, 65)print("---------------------")pflow(88, 85)print("---------------------")pflow(77, 72)print("---------------------")pflow(98, 55)
复制代码



需要根据数字去看看分支执行是否符合预期。

icecream方式:

from icecream import ic
def flow(a: float, b: float): ic() evaluate = "" if a > 90 and b > 90: ic() evaluate = "优" elif a > 80 and b > 80: ic() evaluate = "良" elif a > 70 and b > 70: ic() evaluate = "中" else: ic() evaluate = "及格"
if a < 60 or b < 60: ic() evaluate = "不合格"
ic() return evaluate
flow(98, 92)ic()flow(75, 65)ic()flow(88, 85)ic()flow(77, 72)ic()flow(98, 55)
复制代码



简简单单的一个**ic()**,会把执行的代码位置和函数名称,执行时间等打印出来。


2.4. 定制化输出


最后,icecream还提供了强大的定制化接口,可以按照自己的需要调整输出的内容。

首先,我们注意到通过ic()打印的内容都有一个ic |前缀,实际使用时,我们希望将其替换为和项目相关的文字。比如,我基于manim做个小动画,希望打印的前缀是 manim |

from icecream import ic
def cfg(): ic.configureOutput(prefix="manim -> | ")
ic("something")cfg()ic("something")
复制代码



前缀还可以是动态的,比如用执行时间作为前缀:

from icecream import ic
def cfg(): import time
time_prefix = lambda: time.strftime("%Y-%m-%d %H:%M:%S -> | ", time.localtime()) ic.configureOutput(prefix=time_prefix)
ic("something")cfg()ic("something")
复制代码



除了定义前缀,还可以在输出时添加我们需要的信息。比如,我们希望打印字符串列表字典变量时,顺带输出其长度信息,不用在再去额外打印其长度信息。

from icecream import ic
def add_info(obj): if isinstance(obj, str) or isinstance(obj, list) or isinstance(obj, dict): return f"{obj}(len:{len(obj)})"
return repr(obj)
ic.configureOutput(argToStringFunction=add_info)i = 100f = 3.14s = "abc"ic(i, f, s)
t = (10, 20, 30)l = [1, 2, 3]d = {"A": "abc", "B": 100}ic(t, l, d)
复制代码



从打印内容可以看出,字符串列表字典变量后面有长度len信息,而数值变量和元组,则没有打印长度len信息。

同样,在数据分析时,也可以通过定制,让我们打印pandasDataFrame内容时,顺带打印出其shape信息。

import pandas as pd
def add_info(obj): if isinstance(obj, pd.DataFrame): return f"{obj}\nshape:{obj.shape}"
return repr(obj)
df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})ic(df)
复制代码



3. 总结


总的来说,icecream 提供了一种更加现代和高效的调试方式,让我们更关注需要打印的内容,不用去操心打印的格式。


文章转载自:wang_yb

原文链接:https://www.cnblogs.com/wang_yb/p/18092154

体验地址:http://www.jnpfsoft.com/?from=001

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
扔掉print,用icecream来调试你的代码_代码_快乐非自愿限量之名_InfoQ写作社区