--- jupytext: text_representation: extension: .md format_name: myst kernelspec: display_name: Python 3 language: python name: python3 --- (debugging)= ```{raw} html
``` # Debugging ```{index} single: Debugging ``` ```{contents} Contents :depth: 2 ``` ```{epigraph} "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." -- Brian Kernighan ``` ## Overview Are you one of those programmers who fills their code with `print` statements when trying to debug their programs? Hey, we all used to do that. (OK, sometimes we still do that...) But once you start writing larger programs you'll need a better system. Debugging tools for Python vary across platforms, IDEs and editors. Here we'll focus on Jupyter and leave you to explore other settings. We'll need the following imports ```{code-cell} ipython import numpy as np import matplotlib.pyplot as plt %matplotlib inline ``` ## Debugging ```{index} single: Debugging ``` ### The `debug` Magic Let's consider a simple (and rather contrived) example ```{code-cell} ipython --- tags: [raises-exception] --- def plot_log(): fig, ax = plt.subplots(2, 1) x = np.linspace(1, 2, 10) ax.plot(x, np.log(x)) plt.show() plot_log() # Call the function, generate plot ``` This code is intended to plot the `log` function over the interval $[1, 2]$. But there's an error here: `plt.subplots(2, 1)` should be just `plt.subplots()`. (The call `plt.subplots(2, 1)` returns a NumPy array containing two axes objects, suitable for having two subplots on the same figure) The traceback shows that the error occurs at the method call `ax.plot(x, np.log(x))`. The error occurs because we have mistakenly made `ax` a NumPy array, and a NumPy array has no `plot` method. But let's pretend that we don't understand this for the moment. We might suspect there's something wrong with `ax` but when we try to investigate this object, we get the following exception: ```{code-cell} python3 --- tags: [raises-exception] --- ax ``` The problem is that `ax` was defined inside `plot_log()`, and the name is lost once that function terminates. Let's try doing it a different way. We run the first cell block again, generating the same error ```{code-cell} python3 --- tags: [raises-exception] --- def plot_log(): fig, ax = plt.subplots(2, 1) x = np.linspace(1, 2, 10) ax.plot(x, np.log(x)) plt.show() plot_log() # Call the function, generate plot ``` But this time we type in the following cell block ```{code-block} ipython %debug ``` You should be dropped into a new prompt that looks something like this ```{code-block} ipython ipdb> ``` (You might see pdb> instead) Now we can investigate the value of our variables at this point in the program, step forward through the code, etc. For example, here we simply type the name `ax` to see what's happening with this object: ```{code-block} ipython ipdb> ax array([