Even the smallest characters can introduce big problems
In this article, I will show you a small bug in Python. This is normal, as I have made it so many times. Maybe a dozen, maybe even twenty times – a lot more times than I consider acceptable. But since I’ve made it so many times, I usually spot it easily.
Below, I’ll explain a strategy you can use to spot this and other bugs. While this sounds like our little game, it’s actually how you can approach debugging.
Your job is to find one or more bugs in the code. how to do this? It’s your call, so choose your method. You can, for example:
- Just read the code and traceback, and try to find the bug. This is easier for some snippets than others.
- Copy and paste the code into your IDE, text editor, or whatever else you work with. Then run the app and try to find the bug using traceback. You can also use the simplest non-interactive tools that help with debugging, like
loggingmodules, and so on.
- Copy and paste the code above into your editor/IDE, then use your debugger of choice to find the bug. This is interactive debugging.
Neither of these approaches is better than the others. Each of them teaches different skills, so you should try them all. Perhaps a good approach is to start with method (1), then, if that doesn’t work, try method (2), and if you still can’t find the bug, try method (3).
In this way, you move on to the most advanced method in the easiest and fastest way. This partly reflects real-life coding practice, which is the way I usually proceed. Honestly, I usually immediately switch to the third method when I don’t see the bug after the first glance, that is, when using the first method.
Don’t underestimate the second method, though. This is important and teaches something of extraordinary importance: reading and understanding tracebacks.
So, let’s jump into the code. Try to find the bug. The good news is that it is easy to fix. But you have to find it to fix it. When you do manage to find it, it’s only a matter of seconds to fix it.
Imagine you have a list containing numbers (integers and/or floats), and you want to assign each element a mathematical function. In our case, this will be multiplied by three, which we will apply to the function
multiply(x, by)And then take a square root:
x_squared should be
[1, 9, 49], Instead, we get the following error:
What? What happened now?
It’s time for you to step into action. Take some time, and try to figure out what went wrong. Return to the description above on how to find the bug.
This is the fun part, because you don’t have to worry about anything. Not your bug, not your problem – but your skills will improve!
If you’ve found the bug, congratulations. It is small, small, almost negligible. But it does make a difference, and it breaks the code. The problem is that it’s hard to catch because the exception is not raised where the bug was introduced. Thus, this time, the traceback is not very helpful.
What message can be helpful. Let’s see what it says once more:
Obviously we used
** operand (or, equivalently, the
pow() function) to a list. Sure this isn’t what we wanted to do, but it should help us figure out where the problem happened. Is this?
Not in the beginning. we use
square_root() function, but it seems that the function works fine. Here is the code:
Let’s go back to the traceback once again. it mentions
'list', But why? We certainly didn’t want to take the square root of a list, right? We only have one list; which is defined
x, Let’s double check its definition:
At first glance, the definition seems fine. But look closely: there’s this weird comma (often called a “trailing comma”) after the closing square bracket. Why is it there? And why didn’t Python pick up
SyntaxError, If that were the case, we wouldn’t have a problem finding bugs. But that didn’t happen, which is why the traceback didn’t take us straight to where the bug happened.
A strange thing, a semicolon (
;) instead of this comma will mean nothing, as in Python, you can add semicolons to the ends of lines. Any other character (except whitespace characters) shall mean a
SyntaxError, but apart from
;and whitespace characters, all else would mean a typo and result in
However, this comma at the end of the line changes a lot. it makes
x A tuple, not a list! And what’s funny, the first element of this tuple is the list
[1, 3, 7], Here’s what it looks like:
This comes from the fact that you don’t need to use parentheses when creating a tuple. Here’s an example:
Many developers, including me, use this construct when returning two, sometimes three, elements from a function. For example:
As you see, it doesn’t have any parentheses
return Statement. For me, this version of
Looks so much more natural and better than this:
When defining a tuple without parentheses, you can end it with a comma. Therefore, we get the following:
but beware! Look at the following line, which is very similar to the situation we got in our example:
This is the reason behind the bug in our snippet. When you add a comma after an object to which you want to assign a name, the name refers not to this object but to a newly created tuple instead. Here’s what it looks like:
Such bugs can be created by mistake by putting a comma. This may sound to you as a rare situation, but it happens more often than you think, or at least I’ve created a lot of similar bugs in my coding practice. I find that in most situations – if not all – it happened while I was modifying the code. Does it sound weird?
This. For example, you might introduce such a bug in the following situation – imagine you have a dictionary with some values:
Here, the ellipsis represents more key-value pairs in the dictionary. You decide to move the keys directly into the code. Looks like this:
When doing so, it is quite easy to create the bug we are discussing in this article. Did you see that I actually made it up? it is in the definition of
end_date, The main reason behind this small but important mistake, at least in such situations, is that this kind of modification to the code requires you to create many different things in each line.
Here, you need to remove the definition of
settings dictionary first. Then, you have to remove leading spaces and trailing commas in each line. When you’re not careful – and at least for me, when I have to do such boring things one after the other it’s hard enough to achieve – you can forget to remove one of the many little things that live there. are the end of the line.