Open In App

Debugging with ice cream in Python

Last Updated : 26 Oct, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Do you often use Python print() to debug your code? However, if you want to make a significant improvement, you could use IceCream which would make debugging faster, cleaner, and easier to read. ic(), which is short for IceCream prints both expressions/variable names and their values. ic() is faster to type than print(). The output is highlighted and printed in a structured format. If you want, you can include program context (filename, line number, and parent function) easily. You could effortlessly debug while solving competitive code problems and save a lot of time while debugging.

Installation

To install the IceCream module, you need to open up your terminal or command prompt and type the following command:

$ pip install icecream

After installing the IceCream module, we are ready to use IceCream to debug Python code efficiently.

Why use IceCream to debug

Let’s look at an example where the average of three values is printed by the Python code. 

Note: This is just an example, so just concentrate where and for which variable the print() function is used rather than understanding the code.

Python3




# Python program to print average of three values
a = 3
b = 11
c = 42
  
for i in range(80, 83):
    a = a*i
    b = b*i
    c = c*i
    ans = (a+b+c)/3
    print(a)
    print(b)
    print(c)
    print(int(ans))


Output:

$ python gfg.py
240
880
3360
1493
19440
71280
272160
120960
1594080
5844960
22317120
9918720

When we print the values of a, b, c and ans for debugging purposes, it is difficult to identify which variable corresponds to which output. But what if there are hundreds of values in the output? IceCream is very helpful in these situations for debugging.

Below is the code for printing a, b, c, and ans using IceCream ic().

Note: This is just an example, so just concentrate where and for which variable the ic() function is used rather than understanding the code.

Python program to print average of three values using ic()

Python3




from icecream import ic
  
a = 3
b = 11
c = 42
  
for i in range(80,83):
    a = a*i
    b = b*i
    c = c*i
    ans = (ic(a)+ic(b)+ic(c))/3
    ic(int(ans))


Output:

$ python gfg.py
ic| a: 240
ic| b: 880
ic| c: 3360
ic| int(ans): 1493
ic| a: 19440
ic| b: 71280
ic| c: 272160
ic| int(ans): 120960
ic| a: 1594080
ic| b: 5844960
ic| c: 22317120
ic| int(ans): 9918720

Explanation: Here, ic() is used between the code to print out the values in a structured and simpler method. We are easily able to identify the values of a, b, c and ans in the output.

Simplest Example

Here’s a basic example of how to use the IceCream ic() function. Any data type and data structure that python print() supports can be used with IceCream ic().

Python3




# Python program to print different 
# types of datatypes 
# and data structures using ic()
from icecream import ic
NUMBER = 2008
FLOAT = 95.47
BOOLEAN = True
STRING = "GFG"
LIST = [1, 2, 3, 4, 5]
DICT = {"gfg": "geeksforgeeks", "founder": "Sandeep Jain", }
  
ic(123)
ic(NUMBER)
ic(FLOAT)
ic(BOOLEAN)
ic(STRING)
ic(LIST)
ic(DICT)


Output

ic| 123
ic| NUMBER: 2008
ic| FLOAT: 95.47
ic| BOOLEAN: True
ic| STRING: ‘GFG’
ic| LIST: [1, 2, 3, 4, 5]
ic| DICT: {‘founder’: ‘Sandeep Jain’, ‘gfg’: ‘geeksforgeeks’}

Invoking Python Function using icecream module ic()

Here’s an example to use IceCream with the python function. The implementation of ic() for printing the return value of the function is the same as using the python print function. 

Python3




# Python program to implement ic()
# on functions
from icecream import ic
  
def square(i):
    return i*i
  
ic(square(4))


Output:

$ python gfg.py
ic| square(4): 16

Explanation: Here, ic() prints the function with the argument that is being passed and the return value on the right.

Multiple ways to print ic() in a function

Here are a few different approaches to include ic() in a function to get basically the same result. 

Python3




# Python program to understand different
# ways to print using ic() 
from icecream import ic
  
def multiply1(i, j, k):
    ic(i)
    ic(j)
    ic(k)
    return i*j*k
  
def multiply2(i, j, k):
    ic(i, j, k)
    return i*j*k
  
def multiply3(i, j, k):
    return ic(i)*ic(j)*ic(k)
  
ic(multiply1(1, 2, 3))
ic(multiply2(1, 2, 3))
ic(multiply3(1, 2, 3))


Output:

$ python gfg.py
ic| i: 1
ic| j: 2
ic| k: 3
ic| multiply1(1, 2, 3): 6
ic| i: 1, j: 2, k: 3
ic| multiply2(1, 2, 3): 6
ic| i: 1
ic| j: 2
ic| k: 3
ic| multiply3(1, 2, 3): 6

ic() helps in identifying the block of code that was executed

To determine which block of code was executed, you could use ic() to print the line that was executed. If no arguments are passed in ic(), it will print the line of code that was executed with the parent function, filename and time.

Python3




# Python program to print parent 
# function, filename, 
# and the line number as prefix
from icecream import ic
  
def gfg(value):
    ic()
    if value == True:
        ic()
        return "GFG"
    else:
        ic()
        return -1
ic(gfg(True))


Output:

$ python gfg.py
ic| new.py:6 in gfg() at 18:42:14.916
ic| new.py:8 in gfg() at 18:42:14.917
ic| gfg(True): 'GFG'

Explanation: In the output, Line 1, 6 in gfg() indicates that the program executes the gfg() function and encounters ic() on line 6. Line 2, 8 in gfg() indicates that the program executes the if block and not the else block, as the argument value is passed ‘True’ and encounters ic() on the 8th line of the code. It also prints the time beside it.

ic() default configuration to print the filename, line number, and time as a prefix is false when an argument is passed. But it can be enabled by configuring the output, which we will learn next.

Using includeContext of icecream module

By configuring output as includeContext = True, the output will also print the parent function, filename, and the line number of the ic() which is executed.

Python3




# Python program to configure 
# prefix as parent function,
# filename, and the line number
from icecream import ic
  
ic.configureOutput(includeContext=True)
  
def square(i):
    return ic(i)*i
  
NUMBER = 2008
ic(NUMBER)
ic(square(23))


Output:

$ python gfg.py"
ic| 9.py:11 in <module>- NUMBER: 2008
ic| 9.py:7 in square()- i: 23
ic| 9.py:12 in <module>- square(23): 529

Enable/Disable icecream module

With ic.disable() and ic.enable(), respectively, the output of ic() can be completely turned off and then turned back on.

Python3




# Python program to enable/disable ic()
from icecream import ic
  
ic.disable()
ic(1990)
ic("Hello World")
ic.enable()
ic("GFG")
ic(2008)


Output:

$ python gfg.py
ic| 'GFG'
ic| 2008

Note: Here lines ic(1990) and ic(“Hello World”) are not getting printed.

Using configureOutput parameter in icecream module

IceCream module also enables you to configure a custom prefix. In the below example, we are going to learn how to configure the output prefix as time using a function. 

Python3




# Python program to configure 
# output prefix as time
from datetime import datetime
from icecream import ic
import time
  
ic("gfg")
  
ic.configureOutput(prefix="GFG ")
ic("gfg")
  
def time_format():
    now = datetime.now()
    return f'{now.strftime("%H:%M:%S")} --> '
  
ic.configureOutput(prefix=time_format)
for i in range(1, 6):
    time.sleep(1)
    ic(i)


Output:

$ python gfg.py
ic| 'gfg'
GFG 'gfg'
02:02:41 --> i: 1
02:02:42 --> i: 2
02:02:43 --> i: 3
02:02:44 --> i: 4
02:02:45 --> i: 5

Explanation: In the output, line 1 shows the default output. Line 2 has a prefix ‘GFG’ which was configured in the code. From the 3rd line onwards, we were able to configure output with prefix time. The time shows a delay of 1 second as time.sleep() delays it as shown in the code. Finally, remove all the ic() after the debugging is complete.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads