Debugging in Python

MP 138: Debugging is often learned "on the job", but you can learn a lot with structured practice.

Note: This is the first post in a series about debugging. This post is free to everyone, but the remainder of the series will be available to paid subscribers only for the first 6 weeks. After 6 weeks, the posts will be available to everyone. If you’re already a paid subscriber, thank you for your support. If you currently have a free subscription and would like to see each post as soon as it comes out, please upgrade to one of the paid subscription options.


Debugging is often seen as something you can only learn through experience, but there's a pretty significant problem with learning to debug this way. If you just wait for each new bug to appear, you'll have no idea ahead of time if the bug you're dealing with is simple or complex. If you can learn some general principles and specific techniques before you see your next bug, you'll have a much better chance of resolving many issues quickly. And when more complex bugs arise, you'll have a systematic approach for dealing with them.

There is an element of truth to the idea that experience is important in debugging. Handling a variety of bugs across different projects and environments goes a long way toward making you a better debugger. But there are ways to take a structured approach to practicing debugging. Practicing against a series of increasingly complex bugs can help you build the kind of experience that's useful when approaching real-world bugs.

Series overview

This series will cover the following topics:

  • What is debugging? What's the difference between a bug and an error?
  • How do you systematically approach each new bug that appears in your work?
  • How can you practice troubleshooting a variety of bugs, without just waiting for them to appear?
  • How do you read a short traceback? How do you read longer tracebacks?
  • What is print debugging? When is it okay to use this approach?
  • How do you use a CLI debugger like pdb? How do you use an IDE's debugger?
  • How do you troubleshoot logical errors?
  • How do you investigate errors that might be caused by a bug in a dependency?
  • How do you incorporate testing into your debugging process?

Some of these will be specific to Python, but most of what's covered should serve you well in any language you choose to work with. The syntax you'll see in error messages varies across languages, and the tools can be slightly different as well. But there are more similarities than differences when it comes to effective debugging processes across different languages.

Traceback (most recent call last):   ...   File "/Users/eric/test_code/Pillow/Tests/helper.py", line 22, in <module>         from PIL import Image, ImageFile, ImageMath, features   File "/Users/eric/test_code/Pillow/src/PIL/Image.py", line 2724     if x / y >= aspect: IndentationError: unexpected indent
Tracebacks are confusing to many people who don't have a clear debugging process. This is just six lines; the full traceback was 89 lines long.

Current process

Before we get into specific debugging strategies, take a few minutes to consider your current knowledge and practices:

  • What's the difference between a bug and an error? Why does it matter?
  • Do you have a systematic approach to debugging? Can you write out the steps you usually follow in a short bulleted list?
  • What tools do you reach for when troubleshooting code?
  • What kinds of bugs are easiest for you to resolve? What kinds are most difficult for you?
  • What's the most satisfying bug you've come up with a solution for?
  • Do you write tests to make sure you don't see the same bug twice?

What's next?

In the next post, we'll define "debugging", and a number of other terms that often get used without a clear definition. We'll also lay out a systematic approach to handling a new bug when it first appears. If you don't already have a defined approach to debugging, this next post should be quite helpful.