Debugging with Python Debugger (pdb)

Loading

Debugging is an essential part of software development. It allows you to trace the flow of your code, inspect variables, and pinpoint issues or unexpected behavior. In Python, the Python Debugger (pdb) is a built-in tool that provides an interactive debugging environment, enabling you to examine and control your program’s execution step by step.

In this guide, we will explore how to use pdb for debugging Python programs effectively.


1. Introduction to pdb

pdb is the Python debugger, part of the standard library, that allows you to pause the execution of your code at certain points, inspect variables, and step through the code to identify issues. It provides several commands that give you control over program execution, allowing you to evaluate expressions, set breakpoints, step through the code, and more.


2. Basic Usage of pdb

To use pdb, you need to insert a special statement in your Python code where you want to start the debugger. This statement is:

pythonCopyEditimport pdb; pdb.set_trace()

This line tells Python to pause execution and enter the interactive debugger at that point. Once execution pauses, you can interact with the program, check variable values, step through code, and evaluate expressions.

Example: Basic Debugging with pdb

import pdb

def divide(a, b):
pdb.set_trace() # This will pause execution here
return a / b

result = divide(10, 2)
print(result)

Explanation:

  • The program will execute until it reaches pdb.set_trace(), at which point execution will stop and the interactive debugger will start.
  • You can then inspect variables and step through the code.

3. Key pdb Commands

When the debugger is paused at a breakpoint (after calling pdb.set_trace()), you can use several commands to control execution, inspect values, and navigate the code. Here are some of the most common pdb commands:

Basic Commands:

  • n (next): Executes the next line of code within the same function.
  • s (step): Steps into the function call, allowing you to debug it line-by-line.
  • c (continue): Continues execution until the next breakpoint is encountered.
  • q (quit): Exits the debugger and terminates the program.
  • p (print): Prints the value of an expression or variable.
  • l (list): Lists the source code around the current line.
  • b (breakpoint): Sets a breakpoint at a specific line or function.

4. Setting Breakpoints

You can set breakpoints programmatically using pdb.set_trace() or dynamically using the b command. This allows you to stop execution at a specific line or function.

Example: Setting a Breakpoint with b

import pdb

def calculate_area(radius):
area = 3.14 * radius * radius
return area

def main():
pdb.set_trace() # Initial breakpoint
radius = 5
area = calculate_area(radius)
print(area)

main()

After entering the interactive debugger, you can type:

pythonCopyEditb calculate_area  # Set a breakpoint inside calculate_area

This will pause execution at the beginning of the calculate_area function.


5. Stepping Through Code

Once the debugger is active, you can step through the program line-by-line to track its execution flow.

  • n: Runs the next line within the current function.
  • s: Steps into function calls to allow debugging inside functions.
  • l: Shows the source code around the current line, helping you understand the context.

Example: Using n, s, and l

import pdb

def multiply(a, b):
return a * b

def add(a, b):
return a + b

def main():
pdb.set_trace() # Start the debugger
x = 5
y = 10
result = multiply(x, y)
result2 = add(x, y)
print(result, result2)

main()

Here, you can type n to go line-by-line in the main function, or s to step into the multiply and add functions.


6. Inspecting Variables

The p command is used to print the value of a variable or an expression during debugging.

Example: Inspecting Variables with p

import pdb

def add(a, b):
result = a + b
pdb.set_trace() # Pause execution here
return result

add(10, 20)

At the pdb.set_trace() line, you can use the p command to inspect values:

pythonCopyEditp a  # Prints the value of 'a'
p b  # Prints the value of 'b'
p result  # Prints the result of the addition

7. Using else and finally with pdb

You can use else and finally blocks as usual with pdb to ensure that certain code is executed whether an exception occurs or not. This is especially helpful when you want to perform cleanup tasks or additional checks.


8. Debugging with pdb in the Command Line

You can also run Python scripts in debugging mode directly from the command line without modifying the code by using the -m pdb option.

Example: Running a Python Script with pdb

python -m pdb my_script.py

This will start the Python debugger before executing my_script.py. The program will stop at the first line, and you can interact with the debugger from the command line.

Common Commands in Interactive Mode:

  • list: Displays the current source code.
  • step: Steps into functions called at the current line.
  • continue: Continues running until the next breakpoint.
  • quit: Exits the debugger.

9. Using pdb in IDEs

Many Python IDEs, such as PyCharm, VS Code, and others, have built-in support for debugging, allowing you to set breakpoints, step through code, and inspect variables in a graphical interface. While pdb is useful in the command line, using an IDE’s debugging tools provides a more user-friendly environment.


10. Best Practices for Debugging with pdb

  • Insert pdb.set_trace() strategically: Place breakpoints where you suspect issues might be occurring. Don’t overuse them.
  • Use p to inspect variables: This helps in verifying the values and understanding the program’s state.
  • Step through code logically: Use n to go line-by-line and s to step into functions. This allows you to follow the flow of execution.
  • Remove pdb.set_trace() after debugging: Once debugging is complete, remember to remove pdb.set_trace() from your code before deploying or sharing the script.

11. Example: Full Debugging Session

import pdb

def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n - 1)

def main():
pdb.set_trace() # Start the debugger
result = factorial(5)
print(result)

main()

Steps:

  1. When pdb.set_trace() is hit, the debugger will start.
  2. Use n to move to the next line, or s to step into the factorial function.
  3. Use p n to inspect the value of n during the recursion.
  4. Continue execution with c after inspecting the values.

Leave a Reply

Your email address will not be published. Required fields are marked *