mypy

Debugging Python code using pdb: a crash course.

mypy | 28 October, 2013 02:16

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.

Comments

Re: Debugging Python code using pdb: a crash course.

Jonathan | 28/10/2013, 12:41

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.

Re: Debugging Python code using pdb: a crash course.

Eko | 28/10/2013, 18:04

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

Re: Debugging Python code using pdb: a crash course.

eko | 28/10/2013, 18:04

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

Re: Debugging Python code using pdb: a crash course.

Test | 22/04/2014, 00:59

Great!

Re: Debugging Python code using pdb: a crash course.

eko | 23/04/2014, 14:21

eko

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 :)

Add comment

authimage

 
Accessible and Valid XHTML 1.0 Strict and CSS
Powered by LT - Design by BalearWeb