IceCream – printuj jak PRO

IceCream Logo

Każdy kiedyś użył printa, w celu debugowania swojego kodu, ale czy jest to dobra praktyka? Nie będę się nad tym rozwodził, odpowiedź jest raczej oczywista. Jednakże, co jeżeli chcemy sprawdzić coś naprawdę szybko albo nie mamy dostępu do debuggera? Odpowiedzią jest moduł icecream1, wprowadzający nas w zupełnie nowy wymiar printowania ;). W tym wpisie przedstawię wersję dla języka Python, warto jednak wiedzieć, że projekt ten jest dostępny również w innych językach, dlatego miłośnicy PHP, mogą już zrezygnować ze stosowania funkcji var_dump.

Użycie modułu icecream jest banalnie proste, jak można zauważyć na przykładzie poniżej.

from icecream import ic

foo = "Foo"

def bar():
    ic()
    return ["Bar", "Baz"]

ic(foo)
ic(bar()[0])

output

ic| foo: 'Foo'
ic| ic_playground.py:6 in bar() at 19:23:39.452
ic| bar()[0]: 'Bar'

Jak można zauważyć icecream dostarcza dotakowe informacje przydatne podczas debugowania oraz poprawia czytelność wyjścia, kolorując je w konsoli. Jedno proste wywołanie funkcji pozwala poznać nazwę i zawartość wyświetlanej zmiennej, a bez żadnego argumentu śledzić przebieg wykonywania programu, uzyskując informacje o miejscu oraz czasie wykonania funkcji ic(). Korzystając z ic można łatwo rozdzielić „printy” wykorzystywane do debugowania, od tych, które powinny pozostać w kodzie, łatwo zatem usunąć niepotrzebne wywołania. Twórcy modułu icecream poszli o krok dalej, mianowicie moduł ten wystarczy zaimportować tylko jeden raz, dzięki czemu nie trzeba usuwać niepotrzebnych już importów.

from icecream import install
install()

import bar

ic(bar.BAR)

importowany moduł bar.py

BAR = ic("BAR")

Funkcja install() dodaje funkcję ic() do modułu __builtin__, dzięki czemu możemy korzystać z niej we wszystkich modułach tak jak z każdej innej funkcji wbudowanej. Icecream można też szybko włączyć i wyłączyć, co może być przydatne w celu usunięcia z outputu informacji, aby nie zaśmiecały go po debugowaniu.

ic.disable()
ic.enable()

Icecream pozwala na zmianę formatu wyjścia jak również dodanie do niego dodatkowych informacji, co przedstawione zostało na poniższym przykładzie.

import time
from icecream import ic

def to_string(arg):
    return f"{arg} | {type(arg)}"

time_prefix = lambda: f"{time.time()} | " 

ic.configureOutput(
    argToStringFunction=to_string, 
    prefix=time_prefix, 
    includeContext=True
)

def foo():
    x = "abc"
    ic(x)

foo()
ic()

output

1656616425.1926656 | foo.py:13 in foo()- x: abc | <class 'str'>
1656616425.1987286 | foo.py:16 in <module> at 21:13:45.199

Metoda configureOutput przyjmuje parametry argToStringFunction, prefix i includeContext. Ostatni parametr pozwala na dołożenie do wyjściowego stringa informacji o kontekście wywołania, czyli pliku, linijce, funkcji, czy module, z poziomu którego icecream jest wywoływane. Prefix, jak sama nazwa wskazuje rozszerza komunikat w konsoli o zdefiniowany przez nas prefix, warto zauważyć, że argumentem może być też funkcja, jak zostało to przedstawione w przykładzie. Ostatni parametr argToStringFunction pozwala na skonfigurowanie funkcji odpowiadającej za rzutowanie argumentu przekazanego do funkcji ic() do stringa.

Podsumowując icecream, to ciekawy moduł do debugowania kodu, który powinien przypaść miłośnikom printów przez output bogaty w kontekst oraz fakt, że podczas usuwania z kodu zbędnych wywołań icecream nie da się ich pomylić z printem, który akurat powinien w kodzie pozostać. Oczywiście ic() nie zastąpi debuggera, jednak printa jak najbardziej. Bez wątpienia moduł ten wśród wielu osób znalazł i znajdzie zastosowanie, o czym świadczy ogromna liczba gwiazdek przyznanych projektowi na Githubie. Prezentowane przykłady nie przedstawiają wszystkich możliwości tego modułu, w celach prezentacji wybrałem te moim zdaniem najbardziej przydatne, więcej informacji o icecream znajdziecie TUTAJ.

  1. dokumentacja oraz kod źródłowy modułu: https://github.com/gruns/icecream []