Click here for the sequel of this post
Most of my work at Arbisoft involves developing and debugging custom features for Open edX based systems.
Most of my colleagues here prefer to use PyCharm as their default IDE and editor. PyCharm is among the best Python development tools out there, however, I prefer to use Sublime Text 3 in my workflow so I have to compromise on most of the tooling that PyCharm provides.
One of the most important tools is the debugger, and I’ve had to find alternatives to PyCharm’s debugger. In this post, I’ll give a demonstration of a few tools we can use to debug Python code without relying on an IDE. First on our list is:
pdb – The Python Debugger
pdb ships with every python installation and requires zero third party tooling to get working. We’ll learn how to use it with a small walk-through.
Consider the following code:
def foo(bar=): bar.append("baz") return bar def test1(): response = foo() response = foo() return response
What do you think
test1() will return?
I thought that it would simply return an array with a single element i.e
But instead it returns an array with two elements, both
So, let’s debug this using
pdb comes installed with Python. You can set a breakpoint in your code using the following statement
import pdb; pdb.set_trace()
So, to debug the above code, let’s add a breakpoint using pdb in the
def test1(): import pdb;pdb.set_trace() response = foo() response = foo() return response
We can run this code and we will see that pdb will stop the script at the intended line
~/workspace/test$ python python.py -> response = foo() (Pdb)
Now I can interact with the code by typing commands into the shell. Some of the commands I use are
n (next)– Continues execution until the next line in the current function is reached or it returns
s (step)– Executes the current line and stop at the first possible occasion. This is equivalent to
step intoon most GUI based debuggers
c (continue)– Continues execution and stops only when another breakpoint is encountered.
p (print)– Takes an expression and prints its output
l (list)– Lists the source code of the current file
Let us use these commands to see the flow of our
As you can see in the video above, I step into the second call of
foo and check the value of
bar which turns out to be
['baz'] instead of the initial value
The reason for this is a little tricky: The default values passed to function arguments are evaluated only once in Python.
Meaning that the expressions
 is evaluated as an empty list and the reference of that list assigned to
bar. So, when
foo() is called again, the same reference is stored in
bar which results in
'baz' being appended to the same list. Hence we get
['baz', 'baz'] in
To correct this situation, we can modify code as under:
def foo(bar=None): if bar is None: bar =  bar.append('baz') return bar
Now on every call of
foo() a new empty list
 will be assigned to
bar making sure that our code works as expected.
I realize that
pdb is not an exact replace for PyCharm but in most situations it gets the job done. Also, one advantage of
pdb being a terminal based debugger is that I can use it in any environment even virtualized environments like Docker and Vagrant and remote environments through SSH.
You can read more about how to use
pdb and all features it provides in the official Python documentation here.
I hope I’ve done a decent enough explanation on how to use
pdb. If you have any questions feel free to drop a message and I’ll try to answer them.