The `embed` Debugging Trick in Python and Ctrl+Z
Insert the breakpoint
There’s a useful trick for efficiently debugging Python code. Say if you have a loop like the one below, how to interactively access the list l
at each loop step?
1 | l = [] |
You can insert a “breakpoint” as follows.
1 | # test.py |
Then you run python test.py
in the shell, and an interactive environment will be prompted out like this:
1 | colin ❯ python test.py |
The program stops at the position of embed()
, and you can access variables visible at this point, like:
1 | In [1]: l |
You can also execute most kinds of Python code here, like:
1 | In [2]: l.append(100) |
You can use quit
to continue running the program, and the program will stop at the next breakpoint if there’s any. Ctrl+D is equivalent to this.
1 | In [5]: quit |
Exit the program
Sometimes you insert embed()
inside a loop that will repeat many times, and you just want to exit running the program at some time. But you will find both Ctrl+C and Ctrl+D do not work here, so we can just close the shell and the process will be terminated. :)
Closing the shell works, but we have something better. Say now you are in the interactive environment provided by embed
. You can press Ctrl+Z here, and then you are back to your shell and see something like below.
1 | In [2]: # press Ctrl+Z here! |
BUT we’re NOT done yet! Ctrl+Z just sends the “terminal stop” signal (SIGTSTP) to the foreground running process. The process will not take any more CPU resources, but it still occupies memory and ISN’T dead yet. You can even use fg
to bring it back!
1 | colin ❯ fg |
To terminate the process completely, you need to use kill -9
command, which sends a SIGKILL signal indicating to a service to shutdown immediately. In our case, you can execute kill -9 %1
to terminate the process just suspended by Ctrl+Z.
%1
means “job number 1” in the current shell. You can run jobs
to list all jobs in the current shell, like:
1 | colin ❯ ipython # run ipython in the shell first |
Combining Ctrl+Z and kill -9
is also useful for stopping a process immediately. Because sometimes, after Ctrl+C
, the process will do some post-processing which may take a long time. Then you can use this way to stop it right now.
Deactivate the current embed
Thanks to my friend @Leo‘s reminder, we can use %kill_embedded
in the ipython interactive environment to deactivate the current embed()
but keep others working. For example, in the program below, after stopping at the embed()
in the first loop for 2 times, we can do %kill_embedded
with confirming it and quit
to skip the remaining ones in the first loop, while the embed()
in the second loop still works so we will stop there.
1 | # test2.py |
Execuation log in shell:
1 | colin ❯ python test2.py |
References:
What is effect of CTRL + Z on a unix\Linux application
https://superuser.com/questions/275433/what-does-1-in-kill-1-mean