Python Debugging Techniques

Debugging is a critical skill every Python developer needs to master. Whether you’re troubleshooting a bug or trying to understand why your code isn’t behaving as expected, debugging tools can help pinpoint issues quickly. In this guide, we will cover several debugging techniques including using the built-in pdb debugger, print statements, and the logging module.

1. Debugging with Print Statements

One of the simplest and most common methods of debugging in Python is using print statements. This technique involves printing the value of variables and outputs at different stages of your program to understand its behavior and identify any issues.

1.1 Example of Debugging with Print Statements

Suppose you have the following function that isn’t working as expected:

def add_numbers(a, b):
    result = a + b
    return result

Try It Now

If you are unsure why the function isn’t returning the expected result, you can add print statements:

def add_numbers(a, b):
    print(f'a: {a}, b: {b}')  # Print input values
    result = a + b
    print(f'Result: {result}')  # Print result
    return result

Try It Now

This will give you visibility into the values of a, b, and the result at runtime.

2. Debugging with the pdb Debugger

pdb (Python Debugger) is a built-in Python module that allows you to set breakpoints, step through code, and inspect variables interactively. You can use pdb to pause your program at specific lines and interact with it.

2.1 How to Use pdb

To use pdb, you first need to import it and set a breakpoint in your code using the pdb.set_trace() function. Here’s an example:

import pdb

def add_numbers(a, b):
    pdb.set_trace()  # Set a breakpoint here
    result = a + b
    return result

add_numbers(2, 3)

Try It Now

When the program reaches pdb.set_trace(), it will stop, and you’ll enter an interactive debugger session where you can:

  • n: Step to the next line of code
  • c: Continue execution until the next breakpoint
  • s: Step into a function
  • p: Print the value of a variable (e.g., p a)
  • q: Quit the debugger

2.2 Example of Using pdb

Here’s a more detailed example where we set a breakpoint inside a loop:

import pdb

def calculate_sum(numbers):
    total = 0
    for num in numbers:
        pdb.set_trace()  # Set a breakpoint in the loop
        total += num
    return total

calculate_sum([1, 2, 3, 4, 5])

Try It Now

When you run the above code, the debugger will pause at each iteration of the loop, allowing you to inspect the value of num and total at each step.

3. Using the logging Module

While print statements are simple and effective, they are not always ideal for production code. The logging module provides a more powerful and flexible way to track events, errors, and debug information in your Python programs.

3.1 Basic Logging Example

The logging module allows you to record messages with different levels of severity (e.g., DEBUG, INFO, WARNING, ERROR, CRITICAL). Here’s how you can use the logging module to log messages:

import logging

# Set up logging configuration
logging.basicConfig(level=logging.DEBUG)

def add_numbers(a, b):
    logging.debug(f'a: {a}, b: {b}')  # Log the input values
    result = a + b
    logging.debug(f'Result: {result}')  # Log the result
    return result

add_numbers(2, 3)

Try It Now

In this example, we use logging.debug() to log the values of a, b, and the result. You can change the logging level to control which messages are logged. For example, setting the level to logging.INFO will only log messages with a severity of INFO or higher.

3.2 Logging with Different Severity Levels

The logging module provides several logging levels, which allow you to control the verbosity of your logs:

  • DEBUG: Detailed information, typically useful for diagnosing problems.
  • INFO: General information about the execution of your program.
  • WARNING: Indication of potential issues that may not necessarily cause errors.
  • ERROR: Information about errors that prevent some functionality from working.
  • CRITICAL: Severe errors that cause the program to stop functioning.

Example:

import logging

logging.basicConfig(level=logging.DEBUG)

def add_numbers(a, b):
    logging.debug(f'Adding {a} and {b}')
    if a < 0 or b < 0:
        logging.warning('Negative values encountered!')
    result = a + b
    logging.info(f'Result: {result}')
    return result

add_numbers(2, 3)
add_numbers(-1, 3)

Try It Now

4. Advanced Debugging with External Tools

For more advanced debugging, you can use external tools like:

  • PyCharm Debugger: PyCharm provides an advanced debugging interface with features like breakpoints, step-through execution, variable inspection, and more.
  • VS Code Debugger: VS Code also provides integrated debugging tools for Python, including breakpoints and interactive debugging.

Conclusion

Debugging is an essential skill for any developer, and Python provides powerful tools to help you identify and fix issues in your code. Whether you're using simple print statements, the interactive pdb debugger, or the more robust logging module, these techniques will help you write more reliable and efficient Python programs.