 In this video we are going to look into more detail in how the memory works, in particular when we create variables and reassign variables. So let's first create a new file and call it variables in memory. Let's start with a very easy example. So let's create a variable called var and assign to it the number 20.0. Okay, so let's see what Python does in memory when we execute this line. So as we learned before, at first the right hand side is going to be evaluated, which means in the memory Python will go ahead and will create a rather big object with lots of ones and zeros inside them that mean the number 20.0. And then as we learned before Python tags this box here by saying float here because the content here is a floating point number. So the entire object is a floating point object. That is why we tagged it here. Then let's quickly go back in the lecture notes. On the left hand side, now after the right hand side is done, on the left hand side a new variable is going to be created. It's going to be called var. So Python goes into the left hand side in the memory and tries to find a variable called var which doesn't exist yet. So it creates a new one and puts the name here and then makes the variable reference the object. Okay, so let me briefly go ahead and reiterate certain terms here. So on the right hand side in the memory, we will have all the objects and all the objects always have in common that they have some certain starting location which we call the memory address. That's the identity. Then all objects are going to have a type. Here we have the floating point data type and then all that the objects also have a value and this is what the ones and zeros mean inside the object. In this case for us this means the number 20.0. On the left hand side, we have all the names. Names is what we can look up. So var for example is a name and then we have these arrows here and whenever you see an error in these diagrams that is what we call a reference and the combination of a name var and a reference together that is what we call a variable. Okay, so now let's continue with the example. So what we can now do is we can ask Python, hey Python, what is var? Okay, and Python gives us back 20.0. So what happens in memory? When we have to look up a name, Python immediately goes on the left hand side and tries to find the name here and if it finds it like here var then it simply follows the reference to the object and then what's going to happen is the reference, the starting reference to this object, this is going to be the return value of the expression. Okay, so this is basically what we get back. I throw that in as a red dotted line simply because in JupyterLab if I go back and click into the cell here where I simply evaluated the variable var, I see below in red here, the number two, execution count number two and we get back the return value 20.0. This is why I usually use a red dotted line going from the right hand side to the left hand side to indicate that we are getting something back and whenever we get something back in Python, this always means we are getting back a reference to an object. We never get back the real object so it's always a reference to some object that we get back and then it depends on us what we do with it and here in this cell we don't do anything with it. We simply evaluate the expression, we get back the reference to the 20.0 object and then we don't do anything and by default JupyterLab simply shows us the value. So let's continue the example and let's assign to the variable var the number 20 and now as an integer. So if I execute the cell, what is going to happen in memory is we are going to execute the right hand side first. That means Python will go ahead and will create somewhere in memory a new object with the number 20 in it and the object is of type int for integer. So far nothing else has happened to the 20.0 here. That is important. So now we have two objects in memory. Now the line that we are currently executing is not yet done. We only evaluated the right hand side but the object is already there. Now the left hand side is going to be evaluated. That means we are going to assign to a name called var. So what Python is going to do is it goes on the left hand side and it looks up, do I already have a name called var here? And the answer is of course yes. And whenever this is the case, what Python will do is it will simply remove the reference and then it will go ahead and create a new reference going to this new object. Okay. So now that is what happened. And now the question is what is going to happen to the floating point object here with the 20.0 in it? Well, to be precise, we can't really tell what's going to happen. However, in Python, Python is a language that automates a lot of the memory management. And one of the things Python does is whenever it finds objects in memory that have no reference going to them, that means they have a reference count of zero. That is what we say if you don't have a reference to an object. Then in regular intervals, Python executes what is called the garbage collector. That means it goes ahead and it basically frees the memory. So it basically unallocates the object in a way. Okay. So in other words, Python pretends that this base in memory can now be overwritten again with some other data with some other other object. Okay. And we don't have to do anything that is automatically done in the background by Python. And that is called garbage collection. Okay. And in my diagrams here, what I do is usually when an object has no more references, then I will immediately cross it out, okay, to say, okay, this immediately garbage collected. We cannot even tell that this object ever existed, because there is no way to figure out where it started, because there is no reference anymore. Okay. So if we have no reference to an object, we can not even tell if it ever existed, because we there's no way to follow that where where we should where should we go in memory? Okay, let's continue in the example. And let's learn a little bit new syntax. So at first, maybe quite trivial, let's just ask Python what is why we get back 20.0. This is a simple lookup of the name bar now pointing to a integer object. And now I want to go ahead and I want to multiply the value that is in the variable var by four, and then take the new value 80, and assign it to the variable var again. So what I want to do is the following, I want to create a variable var or update the variable var and assign to it whatever var was before times four. Okay, that is what I want to do. And so let me quickly do that and execute that. And now what happens in memory? And now what I'm going to do is I'm going to give you every detail that is going on in memory now. And some of that in future videos, maybe I will leave out. Okay, but now because that is the first time we look into memory in detail, we are going to look into every detail. So what Python is going to do is it will first evaluate the right hand side, of course. So and the left and the right hand side will be evaluated from left to right. So at first, we are going to evaluate the expression var. This is a simple lookup. This is simply following the var reference here. And then on the right hand side of the multiplication, we have the number four. And now what this means is when Python evaluates that, it creates a new object somewhere in memory. It will put the number four in it. And that is an integer. Okay. And now in the next step, Python goes ahead and basically goes to the object on the left side of the operator. So the left operand and asked this object, hey, 20, do you know how you can multiply yourself with the number four with this object? And then the integer object says, well, the other operand is also an integer. And I know how I can multiply two integers. And how this is done is this is simply going to create a third object, which of course is the number 80. This is of course also going to be an integer. And this is now the result of the right hand side. So sometimes what I say is, I will say the right hand side evaluates to 80. Okay, and what we mean by that is that after a couple of calculations, and possibly a couple of new objects being created on the fly, so to say, we will end up with a new object, which is the final result. And then a reference to the start of this object is going to be the return value. So what we could do here is we could go ahead and use the red dotted line here again, and pretend that somehow a reference to this is going to go to the left hand side. And now it depends on what we do with this reference. And in the example, what we do is we take the reference and assign it to the name var. Okay, so what that means is on the left hand side in the memory, Python will look up is there already a name called var, it finds it. And therefore, it is going to remove the already existing reference. And then it will take the reference that is given back that is so to say the return value, and it will take this reference and update it like this. So the red dotted lines in the future, I don't really draw them that often. This is just to be very precise at the moment. And then we have now two objects, the 20 and the four that have no reference going to them. And what that means is, at some regular interval in the future, the Python garbage collector will find them and identify them as having a reference count of zero and therefore simply remove them or garbage collect them from memory. Okay, and then Python in the future will reuse this area in memory for other objects. Okay, that is what has happened so far. Now, I want to show you a nicer syntax. So instead of saying var will be set to var times four, what we could have done is we could have written var times equals four. Okay, though sometimes you see these so called augmented assignment statements. And what they do is they have like an operator built in and the operation is executed. And then the variable on the left hand side is updated. Okay, so this is the same as saying var is equal to var times four as we saw before, I'm not going to execute this line again, because then I would take the 80 now that I have and multiply by four and I don't want to do that. So if we evaluate simply var right here, we get of course back 80. So I'm not going to run this cell again, but I could have written this to begin with. Okay, and that is a shortcut. So whenever you see an operator equals something, then that simply means simply insert the name that is on the left hand side on the right hand side as the first operand, and then simply connect the rest of the right hand side with this operator that you have here. Okay, so that's just a shortcut. Okay, so let's continue. And let's divide the var a which has a value of 80 by two. Okay, so let's go ahead. And I want to divide it by two. So what I could do is I could use what we just discussed the shortcut, the update version, the augmented update statements. So we could say forward slash equals two. So this would basically go ahead. And that is the same as saying var is set to var divided by two. However, what this would now do is it would take an integer and divide it by two and we learned in a previous video, that dividing with a single forward slash will give us back a floating point number. And here I don't want to have a floating point one. I want to keep it an integer. And I know that 80 divided by two is perfectly divisible. So it is an integer. And in order to do that, we simply use the double forward slash division operator, the integer division operator. And that will keep the result as a integer. So when I execute the next code cell here, what this is going to do in memory is as follows. This will first go ahead and create a new object. Let's put it right here. This is the number two. And of course, that is an integer. And then Python will go ahead and it knows on the left hand side of the division, we have the number 80, this object on the right hand side, this object. So again, Python will go ahead and ask the left hand operand, hey, this object, you object, do you know how you can process this object with division? And then the two integers say, well, yeah, we know that. Okay, so the left integer says, I know how to deal with the other operand. And then 80 divided by two will give us a new result. And the new result will of course be the number 40. And that is also an integer. And now what is going to happen is the reference to this a new object here is the return value of the right hand side, so to say. And then on the left hand side, we are going to update the variable var. So what that means is because var already exists is we remove the reference again, and create a new reference, going to the new 40 object. And then the other two objects here, they are garbage collected. Okay, so now that is what we're left with. And we are going to do one more operation in the example. So first, let's confirm that var is indeed 40. And now let's go ahead and do one more operation and say var plus equals, you will often see plus equals in code. And let's say plus equals two. And then this would be the same as var is equal to var plus two, of course. And we call that sometimes. Let's write it like here to increment a number. Okay, we simply increment var by two in this case. Okay, let's execute this. And this will of course, give us back the number 42. So let's briefly look into into the memory diagram. So this is now going to create a new object with the number two in an integer. Then Python will ask the left hand operand the 40 can you deal with the two and it says yes, this is going to create a new object, which of course is going to be 42. As we all know, this is the answer to everything. And then on the left hand side, the reference, the existing reference is first removed. And a new reference is created going to the 42. And then the 40 and the two objects, they are garbage collected. Okay, so let's go one step further and learn a new syntactical rule that is very easy to learn. So var is now 42. But what if if I wanted to simply remove a name without doing anything else? So let's say I don't want to update var, but I want to simply remove var. How could I do that? There's a special statement in Python called the del statement short for delete. And if I execute it like this by saying del var and execute this, what is going to happen in memory. So here, maybe I should show that briefly del var, we're going to execute this, what is going to happen, Python will go on the left hand side, it will look for a name called var, and it will simply remove it. And also the corresponding reference will also be removed. And what is now not going to happen with the del statement is the 42 object, it actually continues to exist. And now only in a second step, the garbage collector will see that the 42 has no further references. And then of course, the garbage collector will also remove the 42. However, the del statement that that we see here, only removes references or only removes names to begin with, and then the corresponding reference. But the del statement does not delete objects. So in the in the case where this object 42 would have had another reference going to it, this would not have deleted the object. Okay, so the object is only deleted or removed garbage collected, if there is no further reference at the end. Okay, so this is how names work in Python. So let me also emphasize one thing. If you are already if you're watching this video, and you are more experienced Python user or programmer, then what you would know is that Python for small numbers like two and four and so on, does not garbage collect them. So there are a couple of objects in Python in memory when the Python program is running, that are automatically created and that will always be there and that will never be garbage collected and small numbers, small integer numbers are among them. So the diagrams that I show you here in this course, they are a simplification. They are in some cases, not 100% accurate in terms of what is going on in the Python process. But what I teach you is the way of how you should think of the Python process handling the memory. And I want you to see that whenever we write an expression like va plus two, then the two gets created on the fly, we add two numbers together and then the temporary objects, they are removed. So this is an important concept. This is what we call the evaluation process that happens in memory as we evaluate expressions. Okay, so now let's do one more thing. After I now deleted the variable var, what we could do is we could try to access the name. And now of course, we will get a name error because the name obviously does not exist anymore here. And yeah, so this is now the full lifecycle of a variable in memory. This is how variables work, how references work. And yeah, so this is what you should know. And in future videos, we will also have other memory diagrams to learn about other things, of course. So see you in a future video.