Welcome back to a new article in my Intro to Programming series.
In this blog post, we will learn about variables - what they are and why we need them. The concept of variables is fundamental to programming, so it is important that we understand it early on. However, in order to understand variables, we need to first get a basic understanding of how a computer stores things in memory. So in this blog post, we will also learn a bit about how a computer's memory works.
When we briefly introduced data types, I mentioned that you can think of a computer program as simply a sequence of instructions. These instructions act on data that the program is receiving from a variety of external sources, such as user input, files, or databases.
The computer program reads this data from the sources, but in order to do anything with the data, it first needs to store the data (or at least parts of it) somewhere, so it can access it later, when it needs it. It does that in what we call memory.
Why does it need to store the data if it has access to it? Well, because accessing data that is in memory is way, way faster than accessing data that is located in some external location. Think about it this way: even for a human, it is always faster to access information from memory, than to open a browser and search for that information on the internet.
So, just like it does in humans, memory plays a vital role in making computers efficient at their tasks. Think about the following mental exercise. Let's say I ask you to add two numbers, and you say, ok, what are the numbers. I tell you the first one is 17 and the second one is 10.
You cannot do the addition without first memorizing that the two numbers you need to add are 17 and 10 respectively. You store those numbers in your short term memory. While we do not fully understand how memory works in humans, most of us can make use of it without any issues.
As I already mentioned, computers too have memory and that's where they put the data that they need to work with. When you write a computer program you make use of that memory (implicitly or explicitly, depending on the programming language you use) and you can essentially store relevant bits of information in this memory.
You can think of the computer's memory as a very, very large cabinet that holds lots of little boxes. These boxes represent memory slots, so in each of these boxes we can store something.
The above photo of an oak cabinet is a good way to picture this. A simplified version is in the picture below.
We can pretend that each one of these squares is one such memory box and in each of these boxes, we can place some data. For example, let's say we want to store the number 17 in the red box.
Now let's say that in another one of these boxes, I want to store the number 10.
When you want to store something in one of these boxes, you claim it, you name it and you put your desired value in it. The process of claiming a memory box (or location) is essentially a way to reserve that memory location for your own use and inform the operating system (Windows, OS X, Ubuntu, etc.) that no one else is allowed to use it until you unclaim it.
We introduced a few more terms in the paragraph above, so let's take a moment and clarify them. A memory box is usually called memory location in computer science speak. All these memory locations have memory addresses. A memory address is usually a number (integer) that uniquely identifies that memory location (or box, if you prefer the analogy). The concept of memory address is essential. Without memory addresses, it would be impossible to identify memory locations. In this respect, memory addresses are not very different from the numbers you might see on Post Office boxes, which uniquely identify each box.
This process of claiming a memory box and giving it a name is called defining a variable. We typically use the phrase define a variable instead of create a variable. This makes sense, if you think about it, because you are not really creating a memory box - that comes with your computer. What you actually do is equivalent to saying that by definition, the memory location at address X is now reserved for your own use and will be known as so-and-so variable and will store a value that you specified.
To summarize what we covered so far, when these memory boxes are named and have a value inside them, you can think of them as variables. When they're not claimed by any running program and they are not named, they are just locations of available memory. The reality is quite a bit more complicated, but this mental model should help you understand variables.
As an aside, did you ever get a warning that your computer is running low on memory while running some application? Well, what happens is simply that the application is claiming and using a lot of memory boxes because it needs to store a lot of things, and the computer runs out of available boxes. Probably the application is defining a lot of variables, but never "destroying" them to free the memory, that is, to make the memory boxes available to other applications.
What we've done here is offer not a formal definition, but rather an analogy. The details are of course more complex, but this is a good enough approximation for now.
As the name implies, a variable can vary, or, in other words, change its value. Conceptually, we can take out the number 17 from the red box and instead put the number 5 in there. It's the same box and has the same name, but now it just stores a different value.
This process of taking some data (in this case a numeric value) and putting it in one of these memory boxes is called variable assignment - we are assigning a value to the variable. Or, if you want, we are putting some data in a named memory box that we have claimed.
Naming variables is something that a programmer does all the time. It's part science, part art. Variables need to have names, so that both the programmer and the computer running the program know how to refer to them and also where to find them. Imagine a public library where the stacks have no numbers, no names, nothing. Finding anything would be impossible.
In most programming languages we have some restrictions on what constitutes a proper variable name, and we'll cover those rules for Python in just a moment. That's the science part of naming a variable.
For now, though, I want to bring your attention to the art part. How do you name a variable? Fundamentally, variable names should be descriptive. If, for example, you are storing the age of a person in a variable, you should probably name that variable age, not some random other word such as variable. When you look back at your code some months after you first wrote it, it will be much easier to understand if variables have descriptive names. Trust me. Always be considerate to your future self and spend a bit of time and name your variables properly!
Tip: many beginners, in a haste to make progress with their training, take shortcuts and give their variables generic names - or whatever comes first to their mind. I advise you against that. Even if it takes a bit longer, get in the habit of taking a moment and choosing a good name for your variable.
This habit will make you a better programmer in the long run. Variables are like the nouns in English sentences. While the computer will happily keep track and work with whatever name you chose, your fellow humans will have a hard time understanding your code if it's full of variables called var, xyz, my_var, etc.
So variables have a name and can store some data. There are, of course, some rules as to what constitutes a valid variable name. In Python, restrictions exist simply to make the Python Interpreter's job easier. Remember, the Python Interpreter is the piece of software that actually reads your program, converts it from the Python language to a language that the computer understands, and runs it on the computer. This Python Interpreter is very powerful, but it's not all powerful. So, in order for it to work properly, there are some rules that we have to follow when we write programs. One such rule is how we name variables.
Below, we will go over variable naming requirements in Python.
However, they can contain a number, as long as it's not the first character in the name.
Valid: formula1, p4s, etc.
Invalid: 1direction, 34_years, etc.
Spaces are very important in Python - and in many programming languages in general. They are used to separate parts of your code into chunks that can be processed logically by the Python Interpreter. As such, we cannot just add spaces in random places, especially in Python, which is very space sensitive.
If you have two words that make up the variable name (say user and age), simply put an underscore between them instead of a space (e.g. user_age).
Valid: use_age, favorite_number, usd_eur_exchange_rate
Invalid: user age, favorite number, usd eur exchange_rate
There are additional characters that are not allowed, but rather than list them all, I think you should stick to this rule of thumb:
First, what is a keyword? By keywords we mean all the words that have a special meaning in Python. We will talk more about keywords as we advance with this blog series, but if you are curious here's a list of Python keywords (keep in mind that this list is subject to change in newer Python versions):
False, None, True, and, as, assert, async, await, break, class, continue, def, del, elif, else, except, finally, for, from, global, if, import, in, is, lambda, nonlocal, not, or, pass, raise, return, try, while, with, yield
These keywords have special meanings and are clues that the Python Interpreter uses to understand your code. Because they each have a predefined meaning that is crucial to the computer's understanding of your code, you cannot use them to name your own variable. Doing so would essentially change their meaning and the Python Interpreter will complain about it.
One last thing I'll mention about variable names is that, by convention, we write them in all lowercase characters. There's nothing preventing you from using capital letters, but it's just frowned upon in the Python community. As you advance in your programming career, you will notice that programmers have certain things they're very, very picky about. And frankly, that makes sense. Computer code can be very complex, and such rules standardize code to some extent and actually make the task of reading and writing code easier.
I want to take a moment to talk about static vs dynamic typing. You'll very likely run into these terms often, so you should know what they mean. It's actually pretty simple and it has to do with changing the value of variables. Let's go back to our boxes analogy for memory.
We know now that once I define a variable, I can assign a value to it. That is the equivalent of placing a value in that memory box. Later, if I need to, I can change that value - this process is called variable assignment. Well, it turns out that some programming languages limit the way in which you can change variable values.
Particularly, these programming languages do not allow you to store data that is of a different type from the data that we initially had in a variable.
So, for example, if we had our variable assigned to an integer number, let's say 17, these languages will let you later assign it another integer number, let's say 5, but won't let you assign it a floating-point number, or a string, or a boolean etc. They will only let you assign to a variable a value that has the exact same type as whatever value was there to begin with.
These languages are called statically typed. The word static in this context means fixed. The data type of the variable is fixed and it is established when you define the variable.
Now, Python doesn't care what value you store in which variable, and this is partly what makes it so flexible and easy to pick up. The Python programming language will happily let you take your variable and store in it an integer number, and then later on store a string in it, or a list, or a floating-point number.
Languages like Python are called dynamically typed. Dynamic in this context means flexible, able to change.
So there it is:
One thing you may be wondering is why are some languages statically typed and other are dynamically typed. It turns out that both static and dynamic typing have pros and cons. Dynamic typing, for example, is more flexible and faster to write code in - you literally type less code in these languages.
On the downside, consider this: if your program assumes that a certain variable holds an integer, but it somehow gets changed to a string, you'll get a very painful error if, say, you try to divide the value of your variable by 2. So dynamic typing is generally more prone to bugs that are related to these oh-i-didn't-know-you-were-a-string (or a boolean, or a list, etc.) kind of moments.
Static typing is less prone to data type errors. However, programs written in languages that have static typing tend to be longer and more verbose. These languages also tend to have slightly more complicated syntax than dynamically typed languages.
For this section of the blog post, it's best if you follow along in your Jupyter notebook. If you're new to this and get stuck, please follow our guide to getting started with Jupyter notebook.
NOTE: The code is shown using Jupyter notebook style formatting.
In Python you define a variable by simply mentioning it and assigning it a value like so:
favorite_number = 17
In the code above, we named our variable favorite_number and assigned to it the integer value 17. The assignment is done using the = operator. The variable name comes to the left of the equal sign and the value you want to assign to the variable is to the right.
NOTE: When the Python Interpreter reads assignment code, it will always evaluate (i.e. "run") the right side first! We'll see why this matters in a moment.
You can convince yourself that indeed favorite_number now stores the value 17 by just printing it:
What if you want to change the value that you store in the favorite_number variable? Use the = operator again:
favorite_number = 10
NOTE: You'll notice that I put spaces before and after the equal sign (so favorite_number = 10 instead of favorite_number=10). These are not required, but they are recommended to make the code more readable. Even though they're not necessary, you should try to get in the habit of typing them. Your co-workers (and your future self) will be very thankful for that.
I want to show you another trick, this time related to Jupyter. To print the value of a variable, you don't have to actually use print at all, you can just type its name and then run the cell, like so:
When we use this shortcut, Jupyter will mark the result as an output (Out in this case), to make it easier to follow. And, of course, the value that we see on the screen is still 10. Hopefully that makes sense to you. A variable will hold the value we assigned to it until we assign it a different value.
One important thing to understand is that the value you assign to a variable doesn't have to be a simple value, like 10 or 17. It can actually be an expression that can be computed. For example:
favorite_number = 10 * 17
So what happened here? Well, when the Python Interpreter comes across variable assignments, it always evaluates (i.e. calculates) the value to the right side of the equal sign first, and THEN, once it determines the result of that, it assigns the result to the variable. So in this case, it calculates 10 * 17 first, which is 170, and THEN it assigns 170 to favorite_number.
NOTE: This is a very important thing to remember: the right side of an assignment is always evaluated first.
Let's assign favorite_number to 10 again.
favorite_number = 10
Because ultimately variables are just references to certain values that are stored in memory, we can actually use them in expressions. For example, we can add favorite_number to favorite_number and we get 20 because 10 + 10 is 20.
favorite_number + favorite_number
What happened here? Well, when the Python Interpreter comes across expressions like this one, it will calculate the result by replacing the names of the variables with whatever value those variables store at that time. So in this case, it replaces the first favorite_number with 10 and the second favorite_number also with 10, and then it computes 10 + 10.
Let me show you something even crazier:
favorite_number = favorite_number + favorite_number
What value do you think favorite_number has now? Let's try to think through this one before we check the value.
First thing, remember, that the Python Interpreter always looks at the right side first. On the right side of the equal sign we have favorite_number + favorite_number. We know from above that favorite_number was 10. So what's favorite_number + favorite_number?
Well, we actually calculated it above, it's 10 + 10, which is 20. So now that we have that, we simply assign 20 to favorite_number. So now favorite_number should be 20. Let's see if we were right:
Yep, we were right.
These lines of code may be confusing a bit at first, but if you get stuck, remember this: always look at the right side of the equal sign first. The result of whatever you have there is what's going to get assigned to the variable in the end.
What happens if we run the same code again?
favorite_number = favorite_number + favorite_number
Why is it 40? Well, remember, above we updated favorite_number to 20. So now we have favorite_number = 20 + 20, which is 40. Hopefully this makes sense.
Now let's write something a bit more complicated. Let's say we want to build a simple program for a company that exchanges currency. And let's just say that this is a very niche company it only converts Euros to USD. Maybe they're on an airport somewhere and they just exchange Euros to USD.
Let's say that someone comes in and has 100 Euros and wants to exchange it for USD and let's assume that 1 Euro buys 1.25 USD. The exchange rate is probably different in reality, but that's ok for now.
How do we write a program that calculates how much USD should be given in exchange for the 100 Euros? Well, a naive way would be to just say it's 100 * 1.25. And that's 125, which is correct.
100 * 1.25
But a better way to do it is the following:
euro = 100
euro_usd_exchange_rate = 1.25
usd = euro * euro_usd_exchange_rate
In the code above, we store the Euro amount in a variable, let's call that euro. We also store the exchange rate in another variable, called euro_usd_exchange_rate, which we assign the value 1.25 meaning one euro buys a dollar and 25 cents.
So now, we can easily compute the USD amount like this: usd = euro * euro_usd_exchange_rate and we can print out the result, now stored in the variable called usd.
Now, why is this better? Isn't it more code?
This solution does indeed involve more code, but it's better because most of the program logic is not dependent on specific numbers. As you can see in the code above, the part where I'm actually calculating how much USD to give in exchange for Euros, doesn't depend on how many Euros I have, and also doesn't depend on what the exchange rate is. Because it uses variables, and those variables can store any values, the code will work for any amount of Euros and any exchange rate.
This is key because while right now we manually store the amount of Euros we have and the exchange rate in these variables, in the future we'll learn how to read these values as inputs. If we can read the values as inputs and assign the values we read to these variables, our program will work for any user given input!
And that's the beauty of writing computer code: good programs solve categories of problems, not just individual problems. In our case, a good currency exchange program will work no matter what the foreign currency amount is and what the exchange rate is.