Debugging in Python

When mentioning debugging, this means there may be a bug in the middle. Well, I don't mean a bug one might find in a house—what I mean here is a programming bug!

Before moving further with this tutorial, let's get some terms out of the way. Let's briefly define what we mean by a bug and debugging

Bugs

A bug in computing could occur both in software and hardware, but our focus here is on software. Let me quickly mention a belief on where the term bug might have originated. It is believed that the first use of the term bug in computing was when a real bug (moth) was found in one of the relays of the Mark II computer. The term bug was also used at the end of the 19th century to describe technical glitches.

Bugs in software cause the program to produce unintended behavior. It is a term commonly used to refer to an error with unknown location and reason, and they can cause severe issues (i.e. crashing a program).

In this situation, debugging comes into play.

Debugging

Well, one may say that the best way to avoid any issues is not to generate bugs in the first place. But this is unfortunately rather rare, and it's not easy to generate a clean program from the beginning. Having bugs is a normal situation you would fall into.

Debugging is the process of locating, analyzing, and correcting any bug (error) you might encounter. The ultimate goal of debugging is to remove such bugs, and to produce a program that runs and behaves as intended. It is important to note here that most of the time will be spent on locating the bug since, as we mentioned above, it originally has an unknown location.

To have an idea of how difficult debugging could be, see what Brian W. Kernighan had to say:

Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?

Handling Python Exceptions

An exception is an object which indicates that we have a bug (error). In other words, Python uses exceptions in order to communicate that there are bugs in the program. This would be the localization part of the debugging process. Receiving the exception object and performing the necessary actions for dealing with the bug refers to handling the exception. This would be the analyzing and correcting steps in the debugging process.

The try Statement

Python's try statement is used for exception handling and has two forms: try/except and try/finally. In the first case, the try clause can be followed by one or more except clauses, while in the latter case, it can only be followed by only one finally clause.

try/except

The try/except syntax is as follows:

The body of the try clause will contain code that might generate an exception, provided that if an exception was generated, all the statements in the block are skipped. On the other hand, the body of the except clause is called the exception handler, as it is used to catch the exception. The except block code will only be executed if an exception has been generated, otherwise the block will be skipped. You can use built-in exceptions as shown in the Python Standard Library

Let's take an example to make things clearer. Say we were asked to enter a denominator in a division formula. Since dividing by zero is not allowed, let's write a try/except statement that checks if there is a division by zero, and prints a message if this error occurred.

If you input the value 5, for instance, you would get the following output:

Now, try to enter the value 0 as input. What output will you get in this case?

try/finally

try/finally is another way to write the try statement in Python. finally clauses are called clean-up/termination clauses since they always have to be run regardless of whether an exception occurred in the try block.

Let's try the example in the above section, but with the finally clause:

Notice that when you enter the value 5 as input, for instance, you would get the following output:

The raise Keyword

The raise keyword is another way to handle exceptions in Python. In this case, you will be able to raise your own exceptions—that is exceptions that are raised when an issue outside the scope of expected errors occurs.

Let's look at an example of using the raise keyword to understand the concept more.

In this example, if you enter a number outside the allowed range, the print statement in the except block will be executed.

Go ahead, try some values and check the output.

The traceback Module

Python's traceback module is another way to handle exceptions in Python. It is basically used to print stack traces of a program after an exception occurs. The traceback contains the error message, the number of the line that caused the error, and the call stack, that is the sequence of the function calls that led to the error.

Let's take an example that generates a traceback:

If you run this script, you will get an output that looks as follows:

Notice that the bug (error) happened on line 2 in the createException function. Notice also that the call stack can help us in tracking which call led to the error, which in this case is the call which occurred in line 4.

The tutorial is getting longer, and I would like to stop at this point. As you have seen, debugging programs is really a natural and regular thing to do, and I believe that the types of errors you saw in this tutorial sound familiar, don't they?

There are other ways of debugging a Python program and handling exceptions. A well-known way, for instance, is the assert statement

Happy debugging!

Tags:

Comments

Related Articles