Python Debugger with Examples


1. Python Debugger

In this tutorial on Python Debugger, we will learn about pdb, the Python module for debugging your Python code. If you face any doubt in between this Python Debugger tutorial, Please comment. Let’s begin.

Python Debugger

Python Debugger

2. Introduction to Python Debugger

The Python debugger is an interactive source code debugger for Python programs. It can set conditional breakpoints and single stepping at the source line level. It also supports inspection of stack frames, source code listing, and evaluation of arbitrary Python code in any stack frame’s context. Other facilities include post-mortem debugging.

To aid us in our purpose, we have the ‘pdb’ module. We must import it.

>>> import pdb

Read: Python Regular Expressions | Python Regex Tutorial

3. Example of Python Debugger

We’ll start with an example as we begin to explain what the Python debugger really does.

We get to the desktop, and create a file ‘demopdb.py’ with the following contents:

import pdb
x=8
def power_of_itself(a):
return a**a
pdb.set_trace()
seven=power_of_itself(7)
print(seven)
three=power_of_itself(3)
print(three)

First, let’s see what this code does. We first import pdb. Then, we define a variable ‘x’ with the value 8. Next, we define a function ‘power_of_itself’ that returns a number to its own power.

Now here, we slip in a breakpoint in the code; we enter the debugger. The next statement is a call to ‘power_of_itself’, with the argument 7, storing the return value into the variable ‘seven’. After that, we print the value of ‘seven’. Finally, we store the return value of power_of_itself(3) into the variable ‘three’, and print it out.

Now, let’s save this as ‘demopdb.py’ on the Desktop, and switch to the command prompt(cmd).

Read: Python Frameworks

4. In the Command Prompt

Once in the Command Prompt(type cmd in Search), get to the Desktop using the ‘cd’ command:

Microsoft Windows [Version 10.0.16299.309]

(c) 2017 Microsoft Corporation. All rights reserved.

C:\Users\lifei>cd Desktop
Now, we run our program here using the ‘python’ command for the command prompt:
C:\Users\lifei\Desktop>python demopdb.py
> c:\users\lifei\desktop\demopdb.py(6)<module>()
-> seven=power_of_itself(7)
(Pdb)

As you can see, the prompt is at the first line after the breakpoint we set in our code. This is a call to ‘power_of_itself’ with the argument 7. Now we’re at the debugger, and we can type in some debugger commands to proceed with the debugging.

(Pdb) l
1    import pdb
2    x=8
3    def power_of_itself(a):
4        return a**a
5    pdb.set_trace()
6 -> seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb)

l, here, lists out the source code. It points at line 6, because that is where we’re at right now. Now, if we type ‘n’, it will execute until the next line in this function, or until it returns.

(Pdb) n
> c:\users\lifei\desktop\demopdb.py(7)<module>()
-> print(seven)
(Pdb)

As you can see, now, it’s at line 7, which prints the value of ‘seven’. It has executed line 6. At this point, we decided we wanted to check some values.

(Pdb) seven
823543
(Pdb) x
8
(Pdb)

What if we had a variable ‘n’ in our code? Wouldn’t typing ‘n’ be considered a command, instead? For this, we’d do ‘p n’.

To add another breakpoint, we use the command ‘b’.

(Pdb) b 8
Breakpoint 1 at c:\users\lifei\desktop\demopdb.py:8
(Pdb)
But that doesn’t mean we’re at line 8 now:
(Pdb) l
2    x=8
3    def power_of_itself(a):
4        return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7 -> print(seven)
8 B   three=power_of_itself(3)
9    print(three)
[EOF]
(pdb)
(Pdb) b
Num Type         Disp Enb Where
1   breakpoint   keep yes at c:\users\lifei\desktop\demopdb.py:8
(Pdb)
To clear all breaks, we type ‘cl’. And then when it asks for a confirmation, type ‘y’.
(Pdb) cl
Clear all breaks? y
Deleted breakpoint 1 at c:\users\lifei\desktop\demopdb.py:8
(Pdb)

We can also add a breakpoint at a function declaration:

(Pdb) b power_of_itself
Breakpoint 2 at c:\users\lifei\desktop\demopdb.py:3
(Pdb) b
Num Type         Disp Enb Where
2   breakpoint   keep yes at c:\users\lifei\desktop\demopdb.py:3
(Pdb)

When we type ‘c’, the command prompt starts execution, and keeps executing until it reaches the first breakpoint. In our last step, we added a breakpoint at the declaration of ‘power_of_itself’. That is why it stops here. Look:

(Pdb) l
1    import pdb
2    x=8
3 B   def power_of_itself(a):
4 ->     return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb)

We’re at line 4.

Okay, let’s see what commands we have for the Python debugger.

Read: Best Python Libraries

5. Python Debugger Commands for the Command Prompt

Let’s take a look at some of the most important Python debugger commands.

a. h(elp) [command]

Typing in ‘h’ will display help about all available debugger commands.

(Pdb) h

Documented commands (type help <topic>):

========================================

EOF    c        d    h    list    q    rv    undisplay

a    cl        debug    help    ll    quit    s    unt

alias    clear        disable    ignore    longlist    r    source    until

args    commands    display    interact    n    restart    step    up

b    condition    down    j    next    return    tbreak    w

break    cont        enable    jump    p    retval    u    whatis

bt    continue    exit    l    pp    run    unalias    where

 

Miscellaneous help topics:

==========================

exec  pdb

(Pdb)

b. w(here)

‘w’ prints a stack trace, with the most-recent frame at the bottom.

(Pdb) w
c:\users\lifei\desktop\demopdb.py(8)<module>()
-> three=power_of_itself(3)
> c:\users\lifei\desktop\demopdb.py(4)power_of_itself()
-> return a**a
(Pdb)

c. d(own) [count]

‘d’ moves the current frame count down by a certain number of levels, in the stack trace, to a newer frame. The default for this count is 1.

d. u(p) [count]

This moves the current frame count up by a certain number of levels, up in the stack trace, to an older frame. Again, the default for this count is 1.

e. b(reak) [([filename:]lineno | function) [, condition]]

‘b’ informs us about the breakpoints in our code.

With a line number after it, it adds a breakpoint at the line number.

With a function name after it, it adds a breakpoint at the first line under the function declaration.

f. tbreak [([filename:]lineno | function) [, condition]]

This adds a temporary breakpoint. When first hit, the command prompt removes it. Okay, time for a tea-break (pun intended).

g. cl(ear) [filename:lineno | bpnumber [bpnumber …]]

This clears all breakpoints from our code.

h. disable [bpnumber [bpnumber …]]

The ‘disable’ command disables the breakpoints given as a list of breakpoint numbers. When we disable a breakpoint, it stays in the list of breakpoints, and we can re-enable it when we want.

(Pdb) b 7
Breakpoint 1 at c:\users\lifei\desktop\demopdb.py:7
(Pdb) b
Num Type         Disp Enb Where
1   breakpoint   keep yes at c:\users\lifei\desktop\demopdb.py:7
(Pdb) b 9
Breakpoint 2 at c:\users\lifei\desktop\demopdb.py:9
(Pdb) b
Num Type         Disp Enb Where
1   breakpoint   keep yes at c:\users\lifei\desktop\demopdb.py:7
2   breakpoint   keep yes at c:\users\lifei\desktop\demopdb.py:9
(Pdb) disable 2
Disabled breakpoint 2 at c:\users\lifei\desktop\demopdb.py:9
(Pdb) b
Num Type         Disp Enb Where
1   breakpoint   keep yes at c:\users\lifei\desktop\demopdb.py:7
2   breakpoint   keep no at c:\users\lifei\desktop\demopdb.py:9
(Pdb)
i. enable [bpnumber [bpnumber ...]]
This enables a breakpoint.
(Pdb) enable 2
Enabled breakpoint 2 at c:\users\lifei\desktop\demopdb.py:9
(Pdb) b
Num Type         Disp Enb Where
1   breakpoint   keep yes at c:\users\lifei\desktop\demopdb.py:7
2   breakpoint   keep yes at c:\users\lifei\desktop\demopdb.py:9
(Pdb)

j. ignore bpnumber [count]

This command sets the ignore count for the specified breakpoint number. The default is 0. When the ignore count for a breakpoint is 0, it becomes active. Other times, the count decrements every time the prompt reaches the breakpoint when it’s enabled, and when any associated condition is true.

(Pdb) ignore 1 2
Will ignore next 2 crossings of breakpoint 1.
(Pdb)

k. condition bpnumber [condition]

This command sets a new condition for the specified breakpoint, before it is honored. This may be an expression which is true. Since it is an optional argument, if we don’t provide it, it makes the breakpoint unconditional by removing any existing condition.

l. commands [bpnumber]

‘commands’ specifies a list of commands for the breakpoint bpnumber.

(Pdb) commands 1
(com) p x
(com) end
(Pdb)

m. s(tep)

This executes the current line, and stops at the first possible chance.

Let’s try executing this program step by step.

C:\Users\lifei\Desktop>python demopdb.py
> c:\users\lifei\desktop\demopdb.py(6)<module>()
-> seven=power_of_itself(7)
(Pdb) l
1    import pdb
2    x=a
3    def power_of_itself(a):
4        return a**a
5    pdb.set_trace()
6 -> seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb) s
--Call--
> c:\users\lifei\desktop\demopdb.py(3)power_of_itself()
-> def power_of_itself(a):
(Pdb) l
1    import pdb
2    x=8
3 -> def power_of_itself(a):
4        return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb) s
> c:\users\lifei\desktop\demopdb.py(4)power_of_itself()
-> return a**a
(Pdb) l
1    import pdb
2    x=8
3    def power_of_itself(a):
4 ->     return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb) s
--Return--
> c:\users\lifei\desktop\demopdb.py(4)power_of_itself()->823543
-> return a**a
(Pdb) l
1    import pdb
2    x=8
3    def power_of_itself(a):
4 ->     return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb) s
> c:\users\lifei\desktop\demopdb.py(7)<module>()
-> print(seven)
(Pdb) l
2    x=8
3    def power_of_itself(a):
4        return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7 -> print(seven)
8    three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb) s
823543
> c:\users\lifei\desktop\demopdb.py(8)<module>()
-> three=power_of_itself(3)
(Pdb) l
3    def power_of_itself(a):
4        return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7    print(seven)
8 -> three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb) s
--Call--
> c:\users\lifei\desktop\demopdb.py(3)power_of_itself()
-> def power_of_itself(a):
(Pdb) l
1    import pdb
2    x=8
3 -> def power_of_itself(a):
4        return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb) s
> c:\users\lifei\desktop\demopdb.py(4)power_of_itself()
-> return a**a
(Pdb) l
1    import pdb
2    x=8
3    def power_of_itself(a):
4 ->     return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb) s
--Return--
> c:\users\lifei\desktop\demopdb.py(4)power_of_itself()->27
-> return a**a
(Pdb) l
1    import pdb
2    x=8
3    def power_of_itself(a):
4 ->     return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9    print(three)
[EOF]
(Pdb) s
> c:\users\lifei\desktop\demopdb.py(9)<module>()
-> print(three)
(Pdb) l
4        return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9 -> print(three)
[EOF]
(Pdb) s
27
--Return--
> c:\users\lifei\desktop\demopdb.py(9)<module>()->None
-> print(three)
(Pdb) l
4        return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7    print(seven)
8    three=power_of_itself(3)
9 -> print(three)
[EOF]
(Pdb)
n. n(next)

‘n’ continues executing until it reaches the current function’s next line, or until the function returns.

Any doubt yet in Python Debugger? Please Comment.

o.  unt(il) [lineno]

When we run this command without an argument, it continues executing until it reaches a line with a number greater than the current. When called with a line number, it continues executing until it reaches a line with a number equal to or greater than that.

(

Pdb) unt 8
823543
> c:\users\lifei\desktop\demopdb.py(8)<module>()
-> three=power_of_itself(3)
(Pdb)
p. r(eturn)

This continues executing until the current function returns.

q. c(ont(inue))

This continues executing, and only stops when it reaches a breakpoint.

r. j(ump) lineno

This jumps to the specified line number. But this is only available in the bottom-most frame, so you can jump back to execute code again.

s. l(ist) [first[, last]]

This lists the current file’s source code.

t. ll | longlist

This lists the source code for the current frame or function.

u. a(rgs)

This prints the arguments for the current function.

(Pdb) ll
1    import pdb
2    x=8
3    def power_of_itself(a):
4        return a**a
5    pdb.set_trace()
6    seven=power_of_itself(7)
7 -> print(seven)
8    three=power_of_itself(3)
9    print(three)
(Pdb) a
(Pdb) r
823543
> c:\users\lifei\desktop\demopdb.py(8)<module>()
-> three=power_of_itself(3)
(Pdb) r
--Call--
> c:\users\lifei\desktop\demopdb.py(3)power_of_itself()
-> def power_of_itself(a):
(Pdb) a
a = 3
(Pdb)
v. p expression
This prints the value of an expression.
(Pdb) p x
8
(Pdb)

w. pp expression

This prints an expression’s value, but pretty-prints it using the pprint module.

Read: File Handling in Python

x. whatis expression

This prints the type of the specified expression.

(Pdb) whatis x
<class 'int'>
(Pdb)

x. source expression

This tries to get the source code for the specified object, and displays it.

(Pdb) source power_of_itself
3    def power_of_itself(a):
4        return a**a
(Pdb)

y. display [expression]

This displays an expression’s value if it changed.

(Pdb) display x
display x: 8
(Pdb) display
Currently displaying:
x: 8
(Pdb)
z. undisplay [expression]

This doesn’t display the specified expression in the current frame.

aa. interact

This starts an interactive interpreter holding all current scope names in its global namespace.

(Pdb) interact
*interactive*
>>> 2+3
5
>>>

ab. alias [name [command]]

This command creates an alias called name that executes command.

(Pdb) alias y p x
(Pdb) y
8
(Pdb)

Here, we created an alias ‘y’ to print ‘x’.

ab. unalias name

This deletes the alias name.

(Pdb) unalias y
(Pdb) y
*** NameError: name 'y' is not defined
(Pdb)

ac. ! statement

This executes a single line of statement in the current stack frame’s context.

(Pdb) p x
8
(Pdb) !x=9
(Pdb) p x
9
(Pdb)

ad. restart [args …]

This restarts the debugged Python program.

ae. q(uit)

This quits the debugger.

(Pdb) q
Traceback (most recent call last):
File "demopdb.py", line 6, in <module>
seven=power_of_itself(7)
File "demopdb.py", line 6, in <module>
seven=power_of_itself(7)
File "C:\Users\lifei\AppData\Local\Programs\Python\Python36-32\lib\bdb.py", line 48, in trace_dispatch
return self.dispatch_line(frame)
File "C:\Users\lifei\AppData\Local\Programs\Python\Python36-32\lib\bdb.py", line 67, in dispatch_line
if self.quitting: raise BdbQuit
bdb.BdbQuit
C:\Users\lifei\Desktop>

Read: Python Virtual Environment

6. Functions of the Python Debugger

The Python debugger also supports some functions.

a. run(statement, globals=None, locals=None)

This will execute statement under the debugger’s control.

>>> import pdb
>>> def add(a,b):
pdb.set_trace()
print("This will add the two values")
print(f"a={a}")
print(f"b={b}")
return a+b
print("Okay, bye")
>>> pdb.run('add')
> <string>(1)<module>()->None
(Pdb)

b. runeval(expression, globals=None, locals=None)

This evaluates expression under the debugger’s control.

c. runcall(function, *args, **kwds)

This calls function with the specified arguments.

d. set_trace()

This lets us enter the debugger at the calling stack frame.

e. post_mortem(traceback=None)

This enters us into post-mortem debugging of the specified traceback object.

f. pm()

This enters the post-mortem debugging of the traceback in sys.last_traceback.

Read: Python Packages

This was all on Python Debugger. Hope you like tutorial on Python Debugger.

7. Conclusion

Now that you know how to debug a program, we want you to try the Python debugger next time you face a problem with your code. Don’t sit and expect to figure it out from scratch in a second; use the ‘pdb’. In this Python Debugger tutorial if you face any query feel free to drop a comment.

Also See:

Python Career Opportunities

Python for Data Science