CS 3723
  Programming Languages  
  5. Python Debugging   


5.1. Fibonacci Numbers: The Fibonacci numbers are the sequence:

    f[0]=0, f[1]=1, f[2]=1, f[3]=2, f[4]=3, f[5]=5, f[6]=8, f[7]=13, f[8]=21, ...

where the sequence starts with 0 and 1, and each subsequent entry is the sum of the two previous ones. Here are four programs to calculate this sequence: a Java, a C, and a Python program, all array based, along with another Python program that is more like a linked list based version. Each program calculates and stores the first 17 Fibonacci numbers in an array (C or Java) or in a list (Python).

Fibonacci Sequence
Python: List as an Array Version Python: List as a Linked List
# fib1.py: like an array
import sys # for sys.stdout.write
n = 17
f = [None]*n # empty array, size n
f[0] = 0
f[1] = 1
for i in range(2,n):
    f[i] = f[i-1] + f[i-2]

for i in range(0,n):
    sys.stdout.write(str(f[i]) + " ")
sys.stdout.write("\n")
# fib2.py: like a linked list
import sys # for sys.stdout.write
n = 17
f = [] # empty list
f.append(0)
f.append(1)
for dum in range(2,n): # dum unused
    # f[-1]=last elt,f[-2]=next to last
    f.append(f[-1] + f[-2])
for a in f:
    sys.stdout.write(str(a) + " ")
sys.stdout.write("\n")
Java Array Version C Array Version
// Fib.java: Java array version
public class Fib { 
   public static void main(String[] args){
      int n = 17;
      int[] f = new int[n];
      f[0] = 0; f[1] = 1;
      for (int i = 2; i < n; i++)
         f[i] = f[i-1] + f[i-2];
      for (int i = 0; i < f.length; i++)
         System.out.print(f[i] + " ");
      System.out.println();
   }
}
// fib.c: C array version
#include <stdio.h>
#define N 17
int main() {
   int f[N];
   f[0] = 0; f[1] = 1;
   int i;
   for (i = 2; i < N; i++)
      f[i] = f[i-1] + f[i-2];
   for (i = 0; i < N; i++)
      printf("%i ", f[i]);
   printf("\n");
}
Common Output
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987


5.2. A Second Approach: Here's an idea for a simpler approach: Use single variables f, g, and h, that will always hold three successive Fibonacci numbers. Also (of course) we will always have h == f + g. So we start f and g equal to the first two Fibonacci numbers: 0 and 1. Then start a loop with the assignment h = f + g. Finally put the new value of h into g, and the value of g into f, and go back around the loop. For example, if f and g are 5 and 8, the h will be 13. Then we put the 13 into g and the 8 into f, so that f and g will be 8 and 13. Then go back around the loop. Here's a Python program that does this (Hey! This should work.):

Simple Python Version: fib.py
# fib.py: simple approach
import sys # for sys.stdout.write
f = 0
g = 1
sys.stdout.write("0 1 ")
while f < 1000:
    h = f + g
    sys.stdout.write(str(h) + " ")
    g = h
    f = g
sys.stdout.write("\n")
Output
% pythn fib.py
0 1 1 2 4 8 16 32 64 128 256 512 1024

But Rats! Look at the output. It's not right, but successive powers of 2. This is a standard debug problem: the program ran but the output is wrong. What to do? There are several approaches. In a simple program like this one, temporary output statements are bound to chase down the problem. But there are several higher-tech Python approaches. One uses a special editor, IDLE, which is available on many Python environments, but not on ours. (Wikipedia says that IDLE has problems and is not liked by everyone.) Instead we'll try a debugger built into Python itself.


5.3. The pdb Debugger: Put an "import pdb" and the statement "pdb.set_trace()" at the beginning of the program, as shown below. This will stop the program and allow many of the standard debugger things: single-step through the program, set breakpoints, examine variables, etc. The example below shows only a few of many options. [See pdb docs for information about pdb from the Python home page. Commands used by the debugger are at the end of the previous link or here: Debugger Commands.]

In particular here, lines 3-4 set up the program to use the debugger starting with the first statement on line 5. Then line 19 starts the program. Each line is presented after "->" as it is ready to be executed (but before execution). Then the debugger prints the prompt "(Pdb)" and waits for a command. "s" means execute the given line and go on to the next. (Lines are presented in the order of execution, not in the order in the program.) "p f,g" means to print the values of those variables before executing the line. Line 33 is prepared to print the value of h, but before that, line 34 asks to print values for f, g, and h, which are printed in red on line 35. Then the "s" on line 36 says to execute lines 33, which prints the "1" on line 37. Finally line 38 shows the next line ready for execution.

Python with Debugger Enabled: fibpdb.py
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
# fibpdb.py: Python with debugger
import sys # for sys.stdout.write
import pdb # for debugging
pdb.set_trace() # start tracing
f = 0
g = 1
sys.stdout.write("0 1 ")
# value of f,g in blue below
while f < 1000:
    h = f + g
    # value of f,g,h in red below
    sys.stdout.write(str(h) + " ")
    g = h
    f = g
    # value of f,g,h in blue below
sys.stdout.write("\n")

Now start the interactive session: % python fibpdb.py -> f = 0 (Pdb) s -> g = 1 (Pdb) s -> sys.stdout.write("0 1 ") (Pdb) s 0 1 -> while f < 1000: (Pdb) p f,g (0, 1) (Pdb) s -> h = f + g (Pdb) s -> sys.stdout.write(str(h) + " ") (Pdb) p f,g,h (0, 1, 1) (Pdb) s 1 -> g = h (Pdb) s -> f = g (Pdb) s
-> while f < 1000:
(Pdb) p f,g,h
(1, 1, 1)
(Pdb) s
-> h = f + g
(Pdb) s
-> sys.stdout.write(str(h) + " ")
(Pdb) p f,g,h
(1, 1, 2)
(Pdb) s
2 
-> g = h
(Pdb) s
-> f = g
(Pdb) s
-> while f < 1000:
(Pdb) p f,g,h
(2, 2, 2)
(Pdb) s
-> h = f + g
(Pdb) s
-> sys.stdout.write(str(h) + " ")
(Pdb) p f,g,h
(2, 2, 4)
(Pdb) s
4 
-> g = h
(Pdb) s
-> f = g
(Pdb) s
-> while f < 1000:
(Pdb) p f,g,h
(4, 4, 4)
(Pdb) s
-> h = f + g
(Pdb) s
-> sys.stdout.write(str(h) + " ")
(Pdb) p f,g,h
(4, 4, 8)
...

Try to figure out what the bug is before going on with this page.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


5.4. The Bug: This is a standard bug that I have often introduced by mistake. Suppose you have values in variables f, g, and h. If you want to move a new value of h into g, and the old value of g into f, you must be aware that the above method is wrong:

Wrong! Correct! Also in Python
    g = h    
    f = g
    f = g    
    g = h
    f, g = g, h    
        (or)
    g, f = h, g

The code on the left moves the new value of h into g as desired, but then that same new value of h is propagated on into f, instead of putting the old value of g into f. On the right is Python's multiple assignment statement in two versions (either one works here). It gets the effect of doing both assignments "at the same time".

Python's fancy multiple assignment statement gives an even simpler version of the Fibonacci program:

Simplest Python Version (?): fibs.py
# fibs.py: short version
import sys # for sys.stdout.write
f, g = 0, 1
sys.stdout.write("0 1 ")
while f < 500:
    f, g = g, f+g
    sys.stdout.write(str(g) + " ")
sys.stdout.write("\n")
Output
% python fibs.py
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

(Revision date: 2015-01-02. Please use ISO 8601, the International Standard.)