Mastering Code Debugging Techniques

PythonPythonBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

Code is never perfect. You will always have bugs. Code debugging is a skill you need to learn.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("`Python`")) -.-> python/BasicConceptsGroup(["`Basic Concepts`"]) python(("`Python`")) -.-> python/DataStructuresGroup(["`Data Structures`"]) python(("`Python`")) -.-> python/FunctionsGroup(["`Functions`"]) python(("`Python`")) -.-> python/ModulesandPackagesGroup(["`Modules and Packages`"]) python/BasicConceptsGroup -.-> python/comments("`Comments`") python/BasicConceptsGroup -.-> python/variables_data_types("`Variables and Data Types`") python/BasicConceptsGroup -.-> python/numeric_types("`Numeric Types`") python/DataStructuresGroup -.-> python/tuples("`Tuples`") python/FunctionsGroup -.-> python/function_definition("`Function Definition`") python/ModulesandPackagesGroup -.-> python/importing_modules("`Importing Modules`") python/ModulesandPackagesGroup -.-> python/using_packages("`Using Packages`") python/ModulesandPackagesGroup -.-> python/standard_libraries("`Common Standard Libraries`") python/BasicConceptsGroup -.-> python/python_shell("`Python Shell`") python/FunctionsGroup -.-> python/build_in_functions("`Build-in Functions`") subgraph Lab Skills python/comments -.-> lab-132737{{"`Mastering Code Debugging Techniques`"}} python/variables_data_types -.-> lab-132737{{"`Mastering Code Debugging Techniques`"}} python/numeric_types -.-> lab-132737{{"`Mastering Code Debugging Techniques`"}} python/tuples -.-> lab-132737{{"`Mastering Code Debugging Techniques`"}} python/function_definition -.-> lab-132737{{"`Mastering Code Debugging Techniques`"}} python/importing_modules -.-> lab-132737{{"`Mastering Code Debugging Techniques`"}} python/using_packages -.-> lab-132737{{"`Mastering Code Debugging Techniques`"}} python/standard_libraries -.-> lab-132737{{"`Mastering Code Debugging Techniques`"}} python/python_shell -.-> lab-132737{{"`Mastering Code Debugging Techniques`"}} python/build_in_functions -.-> lab-132737{{"`Mastering Code Debugging Techniques`"}} end

Debugging Tips

So, your program has crashed...

$ python3 blah.py
Traceback (most recent call last):
  File "blah.py", line 13, in ?
    foo()
  File "blah.py", line 10, in foo
    bar()
  File "blah.py", line 7, in bar
    spam()
  File "blah.py", 4, in spam
    line x.append(3)
AttributeError: 'int' object has no attribute 'append'

Now what?!

Reading Tracebacks

The last line is the specific cause of the crash.

$ python3 blah.py
Traceback (most recent call last):
  File "blah.py", line 13, in ?
    foo()
  File "blah.py", line 10, in foo
    bar()
  File "blah.py", line 7, in bar
    spam()
  File "blah.py", 4, in spam
    line x.append(3)
## Cause of the crash
AttributeError: 'int' object has no attribute 'append'

However, it's not always easy to read or understand.

PRO TIP: Paste the whole traceback into Google.

Using the REPL

Use the option -i to keep Python alive when executing a script.

$ python3 -i blah.py
Traceback (most recent call last):
  File "blah.py", line 13, in ?
    foo()
  File "blah.py", line 10, in foo
    bar()
  File "blah.py", line 7, in bar
    spam()
  File "blah.py", 4, in spam
    line x.append(3)
AttributeError: 'int' object has no attribute 'append'
>>>

It preserves the interpreter state. That means that you can go poking around after the crash. Checking variable values and other state.

Debugging with Print

print() debugging is quite common.

Tip: Make sure you use repr()

def spam(x):
    print('DEBUG:', repr(x))
    ...

repr() shows you an accurate representation of a value. Not the nice printing output.

>>> from decimal import Decimal
>>> x = Decimal('3.4')
## NO `repr`
>>> print(x)
3.4
## WITH `repr`
>>> print(repr(x))
Decimal('3.4')
>>>

The Python Debugger

You can manually launch the debugger inside a program.

def some_function():
    ...
    breakpoint()      ## Enter the debugger (Python 3.7+)
    ...

This starts the debugger at the breakpoint() call.

In earlier Python versions, you did this. You'll sometimes see this mentioned in other debugging guides.

import pdb
...
pdb.set_trace()       ## Instead of `breakpoint()`
...

Run under debugger

You can also run an entire program under debugger.

$ python3 -m pdb someprogram.py

It will automatically enter the debugger before the first statement. Allowing you to set breakpoints and change the configuration.

Common debugger commands:

(Pdb) help            ## Get help
(Pdb) w(here)         ## Print stack trace
(Pdb) d(own)          ## Move down one stack level
(Pdb) u(p)            ## Move up one stack level
(Pdb) b(reak) loc     ## Set a breakpoint
(Pdb) s(tep)          ## Execute one instruction
(Pdb) c(ontinue)      ## Continue execution
(Pdb) l(ist)          ## List source code
(Pdb) a(rgs)          ## Print args of current function
(Pdb) !statement      ## Execute statement

For breakpoints location is one of the following.

(Pdb) b 45            ## Line 45 in current file
(Pdb) b file.py:45    ## Line 45 in file.py
(Pdb) b foo           ## Function foo() in current file
(Pdb) b module.foo    ## Function foo() in a module

Exercise 8.4: Bugs? What Bugs?

It runs. Ship it!

Summary

Congratulations! You have completed the Debugging lab. You can practice more labs in LabEx to improve your skills.

Other Python Tutorials you may like