郭卫东 发表于 2024-5-15 05:04:51

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

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

通过pip安装:
pip install icecream安装之后可以通过打印其版本来验证是否安装成功。
https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544343-1230829304.png
2. 利用示例

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

首先是调试变量,这也是用的最多的场景。
开发中,我们常常需要将变量打印出来以确认是否正确赋值。
print方式:
# 数值和字符串
i = 100
f = 3.14
s = "abc"
print(i, f, s)

# 元组,列表和字典
t = (10, 20, 30)
l =
d = {"A": "abc", "B": 100}
print(t, l, d)
print(t, l, d["A"])

# 类
class c:
    name = "ccc"
    addr = "aa bb cc"

print(c.name, c.addr)https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544435-1201536856.png
icecream方式:
from icecream import ic

# 数值和字符串
i = 100
f = 3.14
s = "abc"
ic(i, f, s)

# 元组,列表和字典
t = (10, 20, 30)
l =
d = {"A": "abc", "B": 100}
ic(t, l, d)
ic(t, l, d["A"])

# 类
class c:
    name = "ccc"
    addr = "aa bb cc"

ic(c.name, c.addr)https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544539-1804641955.png
通过比力,可以看出icecream的几个优势:

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

调试函数输出也是常用的,假如把函数调用也看做一个变量的话,实在这个和上面打印变量类似。
print方式:
def func(a: int, b: int):
    return a + b

print(func(2, 3))https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544375-532230698.png
icecream方式:
from icecream import ic

def func(a: int, b: int):
    return a + b

ic(func(2, 3))https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544540-1850233100.png
2.3. 调试执行过程

接下来是调试执行过程,当代码中有很多分支判断时,我们常常是在各个分支中print不同的数字,
然后用不同的输入看看代码是否按照预期的那样进入不同而分支。
比如,下面构造一个多分支判断的函数,看看分别用print和icecream是怎样调试的。
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)https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544385-1934918424.png
需要根据数字去看看分支执行是否符合预期。
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)https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544413-1983293846.png
简简单单的一个**ic()**,会把执行的代码位置和函数名称,执行时间等打印出来。
2.4. 定制化输出

末了,icecream还提供了强大的定制化接口,可以按照自己的需要调整输出的内容。
首先,我们留意到通过ic()打印的内容都有一个ic | 前缀,
实际利用时,我们希望将其替换为和项目相关的笔墨。
比如,我基于manim做个小动画,希望打印的前缀是 manim |。
from icecream import ic

def cfg():
    ic.configureOutput(prefix="manim -> | ")

ic("something")
cfg()
ic("something")https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544329-966198046.png
前缀还可以是动态的,比如用执行时间作为前缀:
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")https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544408-760427264.png
除了定义前缀,还可以在输出时添加我们需要的信息。
比如,我们希望打印字符串,列表和字典变量时,顺带输出其长度信息,不消在再去额外打印其长度信息。
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 = 100
f = 3.14
s = "abc"
ic(i, f, s)

t = (10, 20, 30)
l =
d = {"A": "abc", "B": 100}
ic(t, l, d)https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544581-53593287.png
从打印内容可以看出,字符串,列表和字典变量后面有长度len信息,
而数值变量和元组,则没有打印长度len信息。
同样,在数据分析时,也可以通过定制,
让我们打印pandas的DataFrame内容时,顺带打印出其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": , "B": })
ic(df)https://img2024.cnblogs.com/blog/83005/202403/83005-20240324104544416-358772557.png
3. 总结

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

[*]Dart: icecream
[*]Rust: icecream-rs
[*]Node.js: node-icecream
[*]C++: IceCream-Cpp
[*]C99: icecream-c
[*]PHP: icecream-php
[*]Go: icecream-go
[*]Ruby: Ricecream
[*]Java: icecream-java
[*]R: icecream
[*]Lua: icecream-lua
[*]Clojure(Script): icecream-cljc
[*]Bash: IceCream-Bash

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 扔掉print,用icecream来调试你的代码