翼度科技»论坛 编程开发 python 查看内容

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

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
print是我们平时写些python小工具时,最常用的调试工具。
因为开发代码时,常常通过print将执行流程、变量的值以及其他关键信息输出到控制台来观察,
以便了解程序执行情况和调试bug。
但是,print的输出过于简单,在输出变量内容,函数调用,执行过程等相关信息时,
往往需要自己手动去补充很多的输出信息的说明,否则很容易搞不清输出的内容是什么。
而今天介绍的icecream,为我们提供了一种更加优雅和强大的方式来调试代码。
它不仅可以自动格式化输出内容,自动添加必要的描述信息,而且使用起来也比print更加简单。
1. 安装

通过pip安装:
  1. pip install icecream
复制代码
安装之后可以通过打印其版本来验证是否安装成功。

2. 使用示例

下面看看icecream如何替换开发中常见的各种print场景。
2.1. 调试变量

首先是调试变量,这也是用的最多的场景。
开发中,我们常常需要将变量打印出来以确认是否正确赋值。
print方式:
  1. # 数值和字符串
  2. i = 100
  3. f = 3.14
  4. s = "abc"
  5. print(i, f, s)
  6. # 元组,列表和字典
  7. t = (10, 20, 30)
  8. l = [1, 2, 3]
  9. d = {"A": "abc", "B": 100}
  10. print(t, l, d)
  11. print(t[0], l[1], d["A"])
  12. # 类
  13. class c:
  14.     name = "ccc"
  15.     addr = "aa bb cc"
  16. print(c.name, c.addr)
复制代码

icecream方式:
  1. from icecream import ic
  2. # 数值和字符串
  3. i = 100
  4. f = 3.14
  5. s = "abc"
  6. ic(i, f, s)
  7. # 元组,列表和字典
  8. t = (10, 20, 30)
  9. l = [1, 2, 3]
  10. d = {"A": "abc", "B": 100}
  11. ic(t, l, d)
  12. ic(t[0], l[1], d["A"])
  13. # 类
  14. class c:
  15.     name = "ccc"
  16.     addr = "aa bb cc"
  17. ic(c.name, c.addr)
复制代码

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

  • 输入效率更高,因为ic比print更容易输入,只有两个字母。
  • 自动带上变量名称,一眼看出打印的是哪个变量的值
  • 变量名称和值用不同的颜色显示,容易区分
2.2. 调试函数输出

调试函数输出也是常用的,如果把函数调用也看做一个变量的话,其实这个和上面打印变量类似。
print方式:
  1. def func(a: int, b: int):
  2.     return a + b
  3. print(func(2, 3))
复制代码

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

2.3. 调试执行过程

接下来是调试执行过程,当代码中有很多分支判断时,我们常常是在各个分支中print不同的数字,
然后用不同的输入看看代码是否按照预期的那样进入不同而分支。
比如,下面构造一个多分支判断的函数,看看分别用print和icecream是如何调试的。
print方式:
  1. def pflow(a: float, b: float):
  2.     print(1)
  3.     evaluate = ""
  4.     if a > 90 and b > 90:
  5.         print(2)
  6.         evaluate = "优"
  7.     elif a > 80 and b > 80:
  8.         print(3)
  9.         evaluate = "良"
  10.     elif a > 70 and b > 70:
  11.         print(4)
  12.         evaluate = "中"
  13.     else:
  14.         print(5)
  15.         evaluate = "及格"
  16.     if a < 60 or b < 60:
  17.         print(6)
  18.         evaluate = "不合格"
  19.     print(7)
  20.     return evaluate
  21. pflow(98, 92)
  22. print("---------------------")
  23. pflow(75, 65)
  24. print("---------------------")
  25. pflow(88, 85)
  26. print("---------------------")
  27. pflow(77, 72)
  28. print("---------------------")
  29. pflow(98, 55)
复制代码

需要根据数字去看看分支执行是否符合预期。
icecream方式:
  1. from icecream import ic
  2. def flow(a: float, b: float):
  3.     ic()
  4.     evaluate = ""
  5.     if a > 90 and b > 90:
  6.         ic()
  7.         evaluate = "优"
  8.     elif a > 80 and b > 80:
  9.         ic()
  10.         evaluate = "良"
  11.     elif a > 70 and b > 70:
  12.         ic()
  13.         evaluate = "中"
  14.     else:
  15.         ic()
  16.         evaluate = "及格"
  17.     if a < 60 or b < 60:
  18.         ic()
  19.         evaluate = "不合格"
  20.     ic()
  21.     return evaluate
  22. flow(98, 92)
  23. ic()
  24. flow(75, 65)
  25. ic()
  26. flow(88, 85)
  27. ic()
  28. flow(77, 72)
  29. ic()
  30. flow(98, 55)
复制代码

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

最后,icecream还提供了强大的定制化接口,可以按照自己的需要调整输出的内容。
首先,我们注意到通过ic()打印的内容都有一个ic | 前缀,
实际使用时,我们希望将其替换为和项目相关的文字。
比如,我基于manim做个小动画,希望打印的前缀是 manim |。
  1. from icecream import ic
  2. def cfg():
  3.     ic.configureOutput(prefix="manim -> | ")
  4. ic("something")
  5. cfg()
  6. ic("something")
复制代码

前缀还可以是动态的,比如用执行时间作为前缀:
  1. from icecream import ic
  2. def cfg():
  3.     import time
  4.     time_prefix = lambda: time.strftime("%Y-%m-%d %H:%M:%S -> | ", time.localtime())
  5.     ic.configureOutput(prefix=time_prefix)
  6. ic("something")
  7. cfg()
  8. ic("something")
复制代码

除了定义前缀,还可以在输出时添加我们需要的信息。
比如,我们希望打印字符串列表字典变量时,顺带输出其长度信息,不用在再去额外打印其长度信息。
  1. from icecream import ic
  2. def add_info(obj):
  3.     if isinstance(obj, str) or isinstance(obj, list) or isinstance(obj, dict):
  4.         return f"{obj}(len:{len(obj)})"
  5.     return repr(obj)
  6. ic.configureOutput(argToStringFunction=add_info)
  7. i = 100
  8. f = 3.14
  9. s = "abc"
  10. ic(i, f, s)
  11. t = (10, 20, 30)
  12. l = [1, 2, 3]
  13. d = {"A": "abc", "B": 100}
  14. ic(t, l, d)
复制代码

从打印内容可以看出,字符串列表字典变量后面有长度len信息,
而数值变量和元组,则没有打印长度len信息。
同样,在数据分析时,也可以通过定制,
让我们打印pandas的DataFrame内容时,顺带打印出其shape信息。
  1. import pandas as pd
  2. def add_info(obj):
  3.     if isinstance(obj, pd.DataFrame):
  4.         return f"{obj}\nshape:{obj.shape}"
  5.     return repr(obj)
  6. df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
  7. ic(df)
复制代码

3. 总结

总的来说,icecream 提供了一种更加现代和高效的调试方式,让我们更关注需要打印的内容,不用去操心打印的格式。
除了python,icecream还有一系列其他语言的接口:

来源:https://www.cnblogs.com/wang_yb/p/18092154
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具