Once you know your debugger, the real work can begin. Here's a short overview of debugging techniques that I have found useful.
The temptation to change the code is almost too strong to resist. Perhaps your application doesn't work, and you don't have a solid idea of where the problem is, but only a hunch. So you start changing code. Suddenly you notice another problem—and so you change more code. Nothing works, so you change some more code...
Eventually, the original bug disappears — or the application simply crashes before it reaches the bug!
So, the golden rule is: ‘Don't change code at random'. Indeed don't change any code at all before you know exactly where the problem is. (I'm not talking about a sprinkling of print statements here, of course.)
There's another point to the maxim ‘don't change your code': you should debug problems now, and not when you've finished writing the application. If you don't fix a bug as soon as you come across it, you'll probably never fix it. And bugs don't disappear because you added more code.
Try to determine the pattern of failures. This pattern might be caused by data or by usage patterns. That's why it is so important to have other people test your software (a cat walking on a keyboard is an excellent input simulator!). You know all the ‘right' paths through your code, so you'll probably never bring it down. Experienced users know those paths, too, which is why software appears to become more stable after people have been using it for a longer time.
Sometimes you simply want to know whether a certain Python construction works at all. Nobody is perfect, and everyone has little things they are perpetually unsure about. Mine is string slicing. I never know what exactly will be returned by "bla.bla"[:-4].
In chapter five of the excellent book The Practice of Programming, Kernighan and Pike advise to try out your hunches with a little bit of code, whenever you wonder whether something works at all. The Python shell window is tailor made for this:
I wonder what happens when...