扔掉print,用icecream來調試你的代碼

print是我們平時寫些python小工具時,最常用的調試工具。
因爲開發代碼時,常常通過print將執行流程、變量的值以及其他關鍵信息輸出到控制檯來觀察,
以便了解程序執行情況和調試bug

但是,print的輸出過於簡單,在輸出變量內容,函數調用,執行過程等相關信息時,
往往需要自己手動去補充很多的輸出信息的說明,否則很容易搞不清輸出的內容是什麼。

而今天介紹的icecream,爲我們提供了一種更加優雅和強大的方式來調試代碼。
它不僅可以自動格式化輸出內容,自動添加必要的描述信息,而且使用起來也比print更加簡單。

1. 安裝

通過pip安裝:

pip install icecream

安裝之後可以通過打印其版本來驗證是否安裝成功。
image.png

2. 使用示例

下面看看icecream如何替換開發中常見的各種print場景。

2.1. 調試變量

首先是調試變量,這也是用的最多的場景。
開發中,我們常常需要將變量打印出來以確認是否正確賦值。

print方式:

# 數值和字符串
i = 100
f = 3.14
s = "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)

image.png

icecream方式:

from icecream import ic

# 數值和字符串
i = 100
f = 3.14
s = "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)

image.png

通過比較,可以看出icecream的幾個優勢:

  1. 輸入效率更高,因爲icprint更容易輸入,只有兩個字母。
  2. 自動帶上變量名稱,一眼看出打印的是哪個變量的值
  3. 變量名稱和值用不同的顏色顯示,容易區分

2.2. 調試函數輸出

調試函數輸出也是常用的,如果把函數調用也看做一個變量的話,其實這個和上面打印變量類似。
print方式:

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

print(func(2, 3))

image.png

icecream方式:

from icecream import ic

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

ic(func(2, 3))

image.png

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)

image.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)

image.png
簡簡單單的一個**ic()**,會把執行的代碼位置和函數名稱,執行時間等打印出來。

2.4. 定製化輸出

最後,icecream還提供了強大的定製化接口,可以按照自己的需要調整輸出的內容。

首先,我們注意到通過ic()打印的內容都有一個ic | 前綴,
實際使用時,我們希望將其替換爲和項目相關的文字。
比如,我基於manim做個小動畫,希望打印的前綴是 manim |

from icecream import ic

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

ic("something")
cfg()
ic("something")

image.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")

image.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 = [1, 2, 3]
d = {"A": "abc", "B": 100}
ic(t, l, d)

image.png
從打印內容可以看出,字符串列表字典變量後面有長度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)

image.png

3. 總結

總的來說,icecream 提供了一種更加現代和高效的調試方式,讓我們更關注需要打印的內容,不用去操心打印的格式。

除了pythonicecream還有一系列其他語言的接口:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章