Now, before you start getting really committed to print and start making friendship bracelets for this
print statement, there's another tool that I really want to talk about, and it's a tool that's bigger,
it's fancier, it's more complex.
So what is it?
It's a debugger.
And we've already seen debuggers a little bit.
So I've already shown you pythontutor.com,
and you've also seen us use the debugger in the Thonny editor right here.
Now in the starting code, we have a function called mutate() that takes a list as the input and then
prints another list at the end.
So what happens is we start out with this b_list being an empty list, and we have a new_item that starts
out being 0.
Then we loop through each of the items in the a_list that comes in through the input, and we multiply
it by 2 and turn that into the new_item.
And then we modify the new_item even further by adding to it a random number between 1 and 3.
Finally, we use a function called add() in our Maths Module, which we created right here,
and it does the simple thing that you created before, which is just to add one number to another.
So we add the new_item that we've got up to now to the item that we're currently looping through,
and finally we add it all to our b_list,
and hopefully, we are able to modify the a_list with this step-by-step approach to end up with a new
list where each of the numbers is modified according to our rules.
Now, unfortunately, at the moment it does not do what we expect it to do,
it just prints out a single number in our list.
So in order to debug and figure out what is wrong with our code to be able to fix it, we're going to
cover how to use the debugger in PyCharm.
Now, debuggers are pretty similar in most of these Intelligent Development Environments such as PyCharm.
So I'm going to use this opportunity to show you a lot of things that will be reusable, even if later
on down the line you choose to use a different code editor.
Now what we do first is we can define what's called a breakpoint.
So a breakpoint can be created in the gutter of our code.
And you might have done it accidentally before.
So when I hover over these line numbers in the gutter, you can see this red dot appears.
And if I decide to go on to line nine and click on that red dot, I've now created a breakpoint and
you can see that breaking line is now highlighted.
So now I'm going to go into the debug run mode by clicking on this little bug here,
and it's going to run my current file,
and it's going to take into account the fact that now I have a defined breakpoint.
So what is a breakpoint do.
Well it basically puts a break on the code at that particular line.
So here is where I'm setting the new_item from 0 to a new value, which is the value of the item
multiplied by 2.
Now you'll see a couple of things show up already in line in our code, which is kind of helpful.
It's showing us at this point, where the code is at, where we've stopped the code on Line 9,
the current value of a_list is this, this big list which we inputted right here.
So this is the input for this function,
and that's showing up right there.
And then it's showing us b_list is still an empty list,
new_item is 0.
An item which is the first item in the a_list that we're looping through right here is equal to 1.
So now what we can do is use the first of the step buttons in the debug console.
So if I click on this one which is called, Step Over, what it's going to do is it's going to execute
my code line by line, stopping at the very next line.
So now that we've executed this line, which we've broken, it's now happened,
and we can see that what's updated is the new_item is no longer equal to 0, but it's now equal to
2, because we took the item which is one, multiplied it by 2, and then set it equal to new_item.
So new item is now equal to 2 instead of 0.
So we can continue stepping over to the next line,
and remember that the highlighted line is the one that's going to be executed next,
and the line above it is the one that just got executed.
So right now we can see that this Line 10 has just been executed,
and we've generated a random integer between 1 and 3, and we've added that number to our new_item.
So now our new_item is equal to 5.
So while we're here we can do something else,
we can look at another one of these buttons.
So if I go ahead and rerun my debugger and I use instead of the Step Over button, I click on the Step
Into button, so it's going to continue executing each line as it goes, line by line,
but when it encounters a line such as Line 10 where we're using another module,
so code in another file, such as this randint() function from the Random Module, when I click Step Into,
it's going to go into the definition of that function, the randint() function in the Random Module from
random.py, which is built in to Python, and it's going to show you how that function works.
So in fact the randint() actually uses another function called randrange().
And if I continue stepping into it it will go and find this function randrange() and show me how that
function works.
Now once you're done exploring this, which can be really helpful because your code relies on code that's
been written by other people,
and if you want to know how they've defined it, how they've created randrange(), then you can read
through their code.
And sometimes it can provide helpful hints for us to figure out what is wrong with our code.
Now, you don't want to continue stepping through other people's code, so when you want to exit, you
click on this button, which is Step Out and we can continue stepping out until we get back to the code
that we want to examine.
So this can be really helpful where we're stepping through the functions,
but more often than not we don't actually want to step into the library functions such as random because
they work the way they do and we can't really modify it.
So we probably haven't made a mistake there.
And what we want to do sometimes, though, is we want to be able to step into code that is in other
files, but only the code that is written by us,
and we want to ignore these library functions written by the Python team.
So how can we do that?
Well, let's repeat from the beginning.
So this button restarts our debug run and again pauses on our breakpoint.
Instead of using this Step Into button, we're going to use the Step Into My Code button, which does
exactly the same thing as step into going line by line, but it ignores the library functions.
For example, that random() function right there, it doesn't take you over to the random.py file.
But now if I click into step into this current Line 11, then it takes me into this file that I created,
math.py, where I created this function called add().
And it shows me that right now I'm trying to add 4 to 2, which was passed over from the previous function
call.
And if I step out of that add() function in the Math Module, I can go back to examine my file.
So this button can be more useful when we have multi file projects,
and we're trying to examine the cause and the relationship of what could be going wrong in our code.
Because very often as our code gets more and more complex, there's more and more relations that start
happening.
And we're sometimes using code that's been defined elsewhere, and chasing it around can be quite difficult.
So those are some of the most important features of the debugger.
And I want you to take a look
also down here, we've got two tabs here, the threads and variables and the console.
So the threads and variables can be really helpful, showing us the values of the variables that we've
got going on.
So for example, just as they've shown up here as these comments, you can also see them in the list
right here.
What's the current value of new_item at this particular time point?
What is the current value of b_list at this particular time point?
And as you can see that as I continue stepping through my code line by line, these values, they update
as they get changed in the code.
So we can actually trace what's happening to each of our variables in their intermediate stages.
And especially for something like a for loop where everything is pretty much hidden,
we don't know what's going on while it's looping.
This can be really, really helpful to help us figure out what's wrong with our code.
So the other tab here is the console.
And you can see that it shows what gets printed during the run of the code.
So for example, if I was to get rid of this breakpoint,
so I can either disable it by clicking it once and it goes into this darker color, or I can keep it
there and simply say mute breakpoints.
Now if we continue running through our code and stepping it through, you'll see that eventually it
ends the loop and goes to the print.
And we can see that print happening in the console.
So we get our console even when we're running in debug mode as well.
So that's pretty much all there is to it, to the major features of a debugger.
The most useful thing, I think, is just simply being able to see these values show up as you go through
the code, stepping through each of the lines.
So now it's your turn to use what you've learned about the PyCharm debugger and figure out what is wrong
with our code.
Why is it not printing out an entire list with 123456 items?
And instead, why is it only modifying and printing out the first item in the list?
So pause the video and complete this challenge.
All right.
So with our breakpoint in its current position let's do another debug run.
And we are going to watch the value of the b_list and see if it's changing the way we expect it to.
So as I step over each of these lines and we're looping through the list, one thing you'll notice is
that the value of b_list is not changing at all.
So at which point does it actually get populated with these new items?
Well, it's on line 12.
So let's disable this and put our breakpoint here instead.
Let's go ahead and resume our program until it runs to this point.
And we can see that b_list is still empty,
and all that's happening is we're appending new_item.
So new_item is currently equal to 42 as we can see here.
And if I step over this line to execute it, you can see that 42 gets added to the b_list,
and then if I step over once more you'll see that print statement execute and that 42 gets printed.
And then that's the end of our code.
So what's happening is that these new items are not being added to the b_list as they're created.
So the only thing we need to do is just to add an indent.
And so often my Python code fails because of an indent, or because of something silly like that, but
with the debugger, it makes it a lot easier to figure out what is the problem.
So if we do another debug run and you watch how this b_list changes now, every time we loop through the
list, once we get to the end of it, that new_item gets added to the b_list, and you can see it's
adding a new_item each time the loop runs.
And that is what we expect to happen.
So a debugger can be really useful.
It's almost like you've put a print statement on all the variables in your code, and you can isolate
a particular time point to see what each of the values are.
And as we become even more experienced, we're going to be using the debugger more and more.