 Hello everyone. So in the last video we talked about the concept of a notional machine and how to think of memory while your Python application is executing. And one of the big emphasis points that we made was that being able to have this notional machine in your head and step through your code bit by bit and have a good working mental model of memory will really help you debug your programs, understand your programs, and eventually optimize your programs. So in this video what I want to do is go through a tracing worksheet. And the purpose of tracing is laid out here at the top of the worksheet. The ability to trace your code is essential for debugging. And given some arbitrary Python code, you should always be able to answer the following questions. What line gets executed next and what is the current state of memory? In other words, what are the values of the variables that are currently assigned to memory? So what we'll do is go through this worksheet through some examples of tracing execution by hand. Now this is not a just for fun exercise and this is not punishment. The idea here is that you should be able to put down on paper the current state of the program. I can't tell you how many times students come to me and they're like, I'm stuck. I don't understand what's happening. I don't know how I got here. Well the first question is that I usually have is, okay, what line is the error happening on? And usually there's a stack tracer, there's some output that they can point to and say, oh well it says error on line 53. The next step to figuring out the cause of that error is to understanding what the state of the system is at that point in time. So you need to be able to articulate, hey, what are the values of variables at that point in time? Because that's going to give you 95% of the time, that's going to give you the answer. You're going to find out that, wait a minute, this variable does not have the value I thought it did. Or I'm trying to read a variable that isn't there yet. So to be able to trace your code manually is a really essential skill for debugging. And then once you do it more and more, then you'll start to build the model of how your program is executing in your head. And you're like, oh okay, well I see that error. I've seen that kind of error before. The most likely explanation is X. I forgot to do X. Okay, so here's what we're going to do. I have given you the notional instruction memory for some small Python programs below. Remember, instructional memory is the area where Python copies your program into and then steps through it. So we're going to trace the execution of this program by filling in the tables below. So what we will do is, and I very strongly advocate that you print this out or otherwise write it down, I'm going to be typing here in my text editor simply because here in my home office I do not have a good way of actually writing down and filling in these tables by hand and showing it to you at the same time. So even if you can't print this out, get a piece of scrap paper and at least lined paper and copy in these tables because that's what you would be doing if you were debugging your own program. You're going to get out a piece of paper and jot this stuff down. And there's a lot of good reason. Your brain makes better mental connections if you actually write the stuff than if you just type it. So get out a piece of paper. What we're going to do is we're going to have a table like this. You're going to create the table if you need to. In the step you're going to write the, you're going to number each step of execution. So generally we're going to start at line one. So this is the first step of execution. Okay, so I'll write step one there. Excuse me. In memory state in this area here, you are going to show the values of all the variables currently in memory after the line of code executes. We're not going to write down variables that are undefined. And then in the next line, we're going to write down which line of instruction memory comes next. Now again, the point of all this is to be able to say definitively at each point of execution, at each step through instruction memory, what are the values of variables? So the first couple of examples are going to be very simplistic and then we're going to get into a loop and maybe we'll illuminate some tricky scenarios. So let's do the first example. Step one, the first step, we are going to assume that we are going to start at line one of instruction memory unless otherwise specified. So starting at line one. Okay, now in memory state, let me boldface this, show the values of all variables after, or excuse me, show all the values of all variables currently in memory, currently in memory as of right now after the line has executed. All right, well we are executing line one first. After line one executes, what's the value of memory? Well, there's been a variable assignment. And that variable points to the integer five. So I'm going to represent it like this, x colon five. You could write x gets equal five, that's fine too. I'm going to do x five because I don't want you to write down the line of code here. I want you to say what value is the variable pointing to in memory? Okay, after this line executes, that's what we're going to put in next line. Which line gets executed next from instruction memory? Well, as you know, this line executes next, line two. Unless something tells Python to do otherwise, Python code executes top to bottom. It executes sequentially, sequential execution, very important concept in computer science. Things like if statements, else statements, for's, while's, function calls. Those things can all make you not go to the next line of code. But unless you run into one of those things, you're going to go to the next line of code. Okay, so the next line of code is two. All right, so the next line of code we are going to execute is line two. Now we are on the second step of execution. The second step means we have jumped to the next line we're going to run, and we run it. Okay, so the second step of execution. Our steps are going to go 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. They're just going to keep increasing. So what is the memory state after line two executes? Well, my first question to you is, is the variable x still in memory? Can you still refer to x? Can you still get its value? Well, yes, the answer is yes. x is still there. Python still knows what it is. And after we execute line two, we now also have the value of y in memory. Okay, so this is the state of memory. We have x, which is pointing to the value 5, and y, which is pointing to the value 10. All right, the next line to execute is going to be line three. We're executing sequentially. So now we are on step three of execution. What do we get here? Well, here we've got sum gets x plus y. Okay, well, 5 is still there, x is still there. The variable y is still there. And now we have a sum, and x plus y, 5 plus 10, sum will have the value 15. Okay. All right, now what's the next line? We've reached the end of our program that's in instruction memory. So we'll denote that with a special statement. We'll just say the next line is none. None. We're done. Or you know what? Let's do that. We'll say done. We are done here. All right. Okay. Easy enough, right? Straightforward. Let's see what happens when we encounter a control statement, a control flow statement. All right, example two. Instruction memory shows us this little piece of code. Take a look at it for a second. Understand what it does. All right, so first step of execution. We're going to execute line one. According to the instructions, we start at line one, unless otherwise specified. So starting at line one, after we execute it, the value of x is 5, right? x equals 5. And the next line is line two. Okay. Moving on, we're onto the second step of execution, this guy right here. We're executing line two. If x mod two, equal equal zero. Okay, so how does this work out? All right. Well, x is still in memory first. Let's get that out of the way. x is being compared. It's using this arithmetic operator. Mod two. So do you recall what mod is? Mod is short for modulo. M-O-D-L-U. Modulo. It's going to go in a strange place here. x is short for modulo, right? And what does the modulo operator do? It gives you the remainder in a division operation. Okay, so five divided by two is two, right? With a remainder of one. Okay, so x mod two is one. And now this line of code asks, you have to know here, what is your order of evaluation in Python? Well, Python takes arithmetic operators like modulo plus minus multiplication before it does comparison operators, Boolean comparison operators. So this comparison operator is equal equal. So is one equal equal to zero? No. Okay, the answer is no. Now, has anything put into memory here? Well, kind of. Two is put into memory for a minute. Python creates a value of two and puts it somewhere. And it creates a value of zero and puts it somewhere. But it's not storing either of these in a variable, right? And what I'm asking you for in memory state is show the values of all variables currently in memory after the line is executed. So this two and zero do not appear in memory after this line executes. But something different does happen. What's the next line of code to execute? Well, x mod two is one. So we're not going to do this line. Instead, you know, this condition is false. So instead what we wind up doing is executing the else block. So I'm going to write down here that the next line to execute is four. This is for simplicity's sake. The next line to execute is else because this condition is not true. So we do the else branch. All right, so moving on, we're done. We've hit the end of this line. The next line to execute is four. But we were on step three of execution. We've done three lines of evaluation. Excuse me, we've done two lines of evaluation so far. Now we're on step three. Else. Else doesn't modify anything. It doesn't modify in anything. It's really just a bookmark. The next line that we will execute then is five. So in step four of execution, we will evaluate line five. Now is x still available in memory? Well, the answer is yes. X is still there. X is outside this if-else block. It is visible to everything inside the block as well. So x is still there, even though we're not using it. And the result gets a value here of the string odd. So the string odd was created somewhere in heap space, somewhere in heap memory. Python grabbed a block, shoved the string odd in there and said result variable, you now point to odd. The next line that we execute, we leave our else block and we're going to execute line number six. We're on step five of execution. Now, what's in memory? X is still five. Result is still odd. Does the print function modify memory? Not for our purposes. No, it's not assigning a variable or reassigning a variable. So everything looks the same. And we have reached the end of our instructions so we are done, done, done. All right, let's go on to the next page and take a look at something a little more complicated. So in these ones, in these examples, I've given you kind of a hint, right? I've given you the correct number of steps. If I ask you to do this on a homework or a quiz, I won't necessarily tell you how many steps there are. So you kind of have to be sure of when you're done. All right, so now let's look at a loop and lists. Okay, so we're a little more sophisticated here. But let's go through our workflow. We're starting at line one, unless otherwise specified. So in step one, what happens? We create a list in memory, and it has inside that list the strings Alice, Bob, and Carol. And then we tell the variable X, hey, point to this list containing the strings Alice, Bob, not Bib, and Carol. You would think my typing would be better after all these years, but it just gets worse. All right, so we have assigned this variable. Nothing special here. So we just go to the next line. Sequential execution. Line two. Now what? For Y gets the integer 0, 1, 2. Okay. Well, X is still hanging around. I'm just going to copy and paste here because I don't want to type this all out again. Or if you're doing this by hand, I'm perfectly happy accepting some shorthand here. You can put quotes here to indicate the same value as you could put the same, something like that, right? Just indicate that the values haven't changed. That's totally fine. But it is important to indicate that X is still there because it can be the case that things go in and out of memory. All right? So X is still there. Y is new. Okay, and we've got 0, 1, and 2 in that list. All right? Next line is 3. Okay, so step three of execution. For I in Y. So this is a for each loop. I is a variable. There's a hint. I is a variable, and it is going to take on the value of each item in Y in each subsequent iteration of this loop. Okay? So X, after this line executes, X is still there. Y is still there. Right? And in fact, Y is unchanged, so we'll put the same for Y. Save ourselves some writing. But now we have a new variable. We have a variable I. I is a variable, in fact. It's kind of temporary, but it's still there. Okay? And what is the value of I? Well, the value of I is 0. Right? For I in Y, 0 is the first value. Okay? For I in Y, I takes on the first value of Y. All right? Okay, so now, next line. Line four. We are going inside our loop. We are inside our loop. X sub I gets X sub I sub 0. Woo! So, you see this bracket operator? We say sub. X sub. Subscript. Subscripting operator. Okay? X is still visible, and it is still the same. Or is it? Hmm. Okay. Let's think about it. How does a Python evaluate? This is an assignment statement. X sub I gets X sub I sub 0. Woo! Well, this is an assignment statement. In Python, assignment statements are evaluated on the right-hand side first. Okay? First. So, the right-hand side of the assignment operator equals gets evaluated first. So, we got to do this first. Okay? Well, let's figure it out. What is this referring to? X sub I. Let me make a comment here. I would be drawing over here in the margins if I could, right? X sub I. Well, what is I at this point? I is 0. X sub 0 is Alice. Alice is at index 0. Okay? So, we are talking about Alice here. The string Alice. X sub 0. Okay? This whole thing, though, is evaluated left to right. So, we do X sub, because the subscripting operators, we've got two of them kind of stacked together here. But, so, and when you've got two things of equal precedence, subscripting operators, pretty high precedence, if you go into chapter one of your book and look. If things have equal precedence, you go left to right. Okay? So, first, X sub I is X sub 0, which is Alice. Okay? All right? So, you know, more or less, we're now we're saying, all right, what's Alice sub 0? Okay? We've replaced X sub I with Alice. Alice sub 0 is what? Well, Alice is a string, and you can subscript strings. So, this says, give me the first or the character at index 0 in your string. That's A. Okay? So, A right here. So, this whole right-hand side of the evaluation becomes just the string A. Okay? Now, whew, we've evaluated the right-hand side, and we assign it to X sub I. Well, what's I? I is still 0. Okay? I sub 0 is, actually, you know what? Let me try something here real fast. Insert to the right. Okay, let's do this. Let's paste this over here. I've got my original thing. And now, let me show what it looks like after we've evaluated that whole, this whole muck. Now, we've got this, right? Now, we've got this. So, X sub I gets A. All right, well, what's I? I is 0. So, X sub 0 gets A. Okay. A lot more sophisticated now, right? A lot more sophisticated now. All right, we have replaced the value at the first, at the 0th index of X with our change string with A. Okay? So, X has changed. The contents of X have changed. So, we've got to show something here. All right. Let's move on. Whew, that was a rough statement. But let's show the rest of the variables in memory. We've got to show all the variables in memory. X is, or Y is the same. We haven't changed it. And I is still 0. I is still the same. Okay? All right, so we've executed line 4. What's next? Well, the end of our for loop, we're going to go back up to line 3. Okay? Loop back around to the for loop. Okay, so now we're up here. Next step of execution. We've only gone through four complete steps of execution, but we've done a lot. All right, what happens here? Well, in this line, we increment I. I gets the next value of Y. Okay? X is unchanged from this line. X is still this. Y is unchanged. We're not really touching Y. I is different now. I is 1. It has taken on the second value in the list Y. Okay? Line 4 again, our happy line 4. And we're on the sixth step of execution. Okay, so line 4. Okay? Do this in depth one more time. Okay? X, here we're line 4. We're going to tweak this side. All right? We do the right hand side of the assignment statement first. And we've got these two subscript operators. Because they're equal precedents, we do the left one first. Okay, so what's X sub I? Well, at this point, I is 1. Okay? So X sub 1 goes here. Okay? What's X sub 1? Well, X sub 1 is Bob. Okay? So we're saying Bob sub 0. And what's Bob sub 0? Well, it's this. The item at the zero with index of Bob. Okay, cool. All right. What's X sub I? Well, X sub I I is 1. Well, the 1th index of X used to be Bob's, but we're going to replace him with this thing that we just evaluated. And we haven't done anything to Carol yet. Okay? All right? Y is unchanged. And I is unchanged. It's still 1. All right. Pop back up to line 3. We haven't finished our for loop yet. We're going to go back up to line 3. Okay, at line 3, for I in Y, X is the same as the previous line. Y is the same as the previous line. And I has changed. I is now 2. For I, now we're up to 2. Okay? Go into our line 4. So I'm not going to go into detail on this. All right? Once we execute line 4, we've got A, B, C. Y is unchanged. We're executing line 4 here. And I is still 2. All right. Million-dollar question. We've gone through all the values of I and Y. We've just finished this. What happens next? Do we go to line 5? The answer is no. Not yet. And you can see this is what Python in fact does. Python goes back to line 3. And it says, hey, basically what it says is, is there any more values in Y that I needs to take on? The answer is no. Y, we've gone through them all, 0, 1, 2. But nonetheless, this line does execute to check and see, hey, did we do it all? The answer is yes. So now that we have done everything, okay, line 9 here, or step 9, excuse me, okay. We're not modifying anybody. X is the same. Y is the same. After this line executes, what is the value of I? We've already done 0, 1, 2. This is the fourth time we've hit this line. What is the value of I? The value of I is still 2. It is the same. It is unchanged. It is still there as well. I is still there. You can still see it. It is still in memory. You could print it out if you wanted to. But what's the next line? Well, we're not going in our loop anymore. We go down here. We go down to line 5. Okay. We've completed our loop. All right. Step 10 of execution. We're printing X. Well, printing does not change the value of variables. I All these things are the same and we are done. Wow. Okay. So we just went up a lot of levels of difficulty there. Okay. So practice, practice this, practice this. Go through this again. Do this example again by yourself. Make sure you're understanding what you're doing. You will have a little bit of a homework question on this. When you get into the homework, when you're confused about the rules. One thing I'll point out to you now before we leave off this video, because it's been a long video. Notice that at every line here, every step of execution in our table, at most one variable is changing. Okay. Look at that again. We create X. We create Y. We create I. We change X. We change I. Change X, change I, change X, change I. Nothing. No changes. No changes. Okay. That's a pattern you will see in Python. In general, in general, almost always you are only going to be changing the value of at most one variable for each step of execution. Okay. So work on your mental models of how Python executes and we'll talk more about types and data and variables in the next video.