Debugging Python code using pdb: a crash course.

pdb (Python Debugger) is a standard debugging utility for Python. If you have been using print statements to debug your Python code so far then you should definitely invest in learning this tool as it will save you time in the long run. 

Let's consider following Python code that contains a bug:

1
2
3
4
5
6
7
8
9
10
11
def flatten(tree, base_list=[]): 
  """Outputs elemetns of the tree as a list in DFS order."""
  for element in tree:
    if isinstance(element, list):
      base_list += flatten(element)
    else:
      base_list.append(element)
  return base_list
 
tree = [1, [2, [3, 4]], 5]
print flatten(tree)

Running this code produces following output:

[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 5]

which is obviously not what we expected. Not let's debug the problem using pdb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
> python -m pdb bug.py
> /tmp/bug.py(1)<module>()
-> def flatten(tree, base_list=[]):
(Pdb) s
> /tmp/bug.py(11)<module>()
-> tree = [1, [2, [3, 4]], 5]
(Pdb) s
> /tmp/bug.py(12)<module>()
-> print flatten(tree)
(Pdb) s
--Call--
> /tmp/bug.py(1)flatten()
-> def flatten(tree, base_list=[]):
(Pdb) s
> /tmp/bug.py(3)flatten()
-> for element in tree:
(Pdb) s
> /tmp/bug.py(4)flatten()
-> if isinstance(element, list):
(Pdb) p element
1 # so far so good, the first element is 1
(Pdb) s
> /tmp/bug.py(7)flatten()
-> base_list.append(element)
(Pdb) s
> /tmp/bug.py(3)flatten()
-> for element in tree:
(Pdb) s
> /tmp/bug.py(4)flatten()
-> if isinstance(element, list):
(Pdb) p element
[2, [3, 4]] # the second subtree is indeed [2, [3, 4]]
(Pdb) s
> /tmp/bug.py(5)flatten()
-> base_list += flatten(element)
(Pdb) s
--Call--
> /tmp/bug.py(1)flatten()
-> def flatten(tree, base_list=[]):
(Pdb) s
> /tmp/bug.py(3)flatten()
-> for element in tree:
(Pdb) s
> /tmp/bug.py(4)flatten()
-> if isinstance(element, list):
(Pdb) print element
2 # first element in the subtree is 2
(Pdb) s
> /tmp/bug.py(7)flatten()
-> base_list.append(element)
(Pdb) s
> /tmp/bug.py(3)flatten()
-> for element in tree:
(Pdb) print base_list
[1, 2] # 1 showed up among subtree elements, bug!

This is a common bug of using non-immutable object as a default value!

Now we can correct our program:

1
2
3
4
5
6
7
8
9
10
11
12
13
def flatten(tree, base_list=None):
  """Outputs elemetns of the tree as a list in DFS order."""
  if not base_list:
    base_list = []
  for element in tree:
    if isinstance(element, list):
      base_list += flatten(element)
    else:
      base_list.append(element)
  return base_list
 
tree = [1, [2, [3, 4]], 5]
print flatten(tree)

Running it produces the intended output:

[1, 2, 3, 4, 5]

Success! We debugged and fixed the problem.




Leave comments

authimage
  • It is easier to debug with graphical debugging tools. I use PyDev for Eclipse. Its integrated debugger allows to step throw lines of code while observing a complete state of your program.

    • Jonathan
  • Nice knowing this feature! I prefer developing my application (if possible) in a console environment, using emacs.
    This tool will equipped me with just the right tool

    • Eko
  • Nice knowing this feature! I prefer developing my application (if possible) in a console environment, using emacs.
    This tool will equipped me with just the right tool

    • eko
  • Great!

    • Test
  • Hi Jonathan,

    I take back my previous comment: it's way easier to develop Python application using IDE. After seriously working with PyCharm and Python Tools for Visual Studio, I can't go back to Emacs and do all the things in console mode.

    Beside interactive debugging, I love the other useful feature of IDE, such as:
    1. Quick completion
    2. Code navigation: go to identifier definition, its usages etc.
    3. ... and Refactoring

    I am not sure the above three important features from IDE can be implemented easily --if it's possible at all!-- in Emacs

    Thanks,
    Eko
    PS : haven't test PyDev by the way. Just PyCharm + PTVS :)

    • eko

Copyright(c) 2017 - PythonBlogs.com
By using this website, you signify your acceptance of Terms and Conditions and Privacy Policy
All rights reserved