Debugging practices
There's a large number of tools to help with debugging, but to be honest you quite often want a quick and simple method to check and solve problems. With that in mind, here's a set of debugging tools that are worth keeping handy.
When writing code, write one line at a time, and think about how you can test it. That way, if anything goes wrong, you know which line it's gone wrong in.
The print()
function is your friend. If some thing isn't working, and you think it is a variable
that's wrong at some point, stick in a whole bunch of prints back from that point to the point the variable was first written to see where the issue arises. Print is also useful for checking loops are looping, and code is actually getting to some point. If code fails mysteriously, the first thing to do is dump in some prints and see
how far it is getting.
Check objects exist before you use them. You'd be suprised how easy it is to end up with objects that
haven't been set up yet and are still just labels (i.e. None
). If they're None
they may not print properly, but you can print their type()
to see. If you don't think a variable
inside an object exists, check both the variable and the object it is in – it may be that the object doesn't
exist yet.
If functions aren't working, check the data passed in is correct. Try the same function with toy data; for example a 3x5 list, rather than a 1000x1000 one. The latter is hard to spot mistakes with. Use non-square 2D containers rather than square ones for testing, as the former pick up issues with dimension indices being the wrong way round.
If code isn't working, and it isn't obvious where the problem is, either cut out everything and slowly add chunks of code in to see what works, or slowly remove chunk by chunk and see when it starts working. If there's a problem with the text file the Python is saved in (for example, it isn't the UTF-8 format), you'll quite often have to strip a file back to Hello World before this will become obvious (for reference, Notepad++ will allow you to save alternative formats as UTF-8).
Unchain complicated function calls and nested function calls. For example, if Python says there is something wrong
with:
a = function1().function2().function3()
or
a = function1(function2(function3()))
the first thing to do is expand both to:
c = function3()
b = function2(c)
a = function1(b)
so Python tells you which call is actually going wrong. You can always
re-compress them later once you've worked out the issue.
Check indents: if the code is running, but doing something odd, the most likely issue is that a dedent has pulled code out of a loop or function it should be indented inside.
Check spellings, especially of variable names. Use a variable explorer to check when variables come into being. If more than one variable with similar names start appearing, it might be a mis-spelling.
Check scope. If Python refuses to recognise a variable or function name you've definitely created, chances are its scope isn't right and it doesn't exist inside the relevant code. In a script this can be as simple as not making the function or variable before it is being used.
If you make changes to a class and they don't seem to be being picked up, test this by first
printing the object you're making from the class (you should see the class name and a set of letters and numbers
representing the memory address of the object); if you're sure the object is of the class you're expecting, override
the invisible __str__(self)
function in the class, and get it to return a relevant string (for
example, the variable you're changing). If you now print the object, you should see whatever you told
__str__(self)
to return, and you know your class changes are being picked up. If they aren't, a common problem
is having copied files to a new location. Python will keep picking up the original position of files you import, so if you've
moved them, the simplest solution is to rename the moved versions and import the new name.
Work through stuff by hand. If all else fails, get out a piece of paper and work through code a line at a time recording what you think the variable values are. This can be suprisingly useful with loop structures especially.