In our earlier tutorial, we discussed the concept of functions — specifically built-in functions, which are the functions and modules that other people have written to help you do lots of things in your code. As you might recall, one big benefit to functions is that they allow you to reuse the same code over and over again, without having to type in all that code everywhere in your program that you need to use it.
In addition to built-in functions (those functions written by other people), Python and most other common programming languages allow you to create your own functions. Creating your own functions has the same benefit of only needing to write code a single time, but it also allows you to customize the function to do whatever you want — as opposed to whatever someone else wants, as with built-in functions.
Here's an example of where custom functions are useful...
Let's say that we wanted to write some code that would print my name and the year I was born. We could do this exactly like we did with the "Hello, World!" code we wrote in Project #1, and our code might look like the following:
Now let's say we expected to print those same lines many times within our code. While we could type those lines over and over again in the code, as you probably could guess, a simpler way would be to create a function that prints those two lines, and then call that function every time we want those lines printed.
So, let's turn the above two lines into a function that we can call from other places in our code...
The first step in creating a function is giving it a name. In this case, let's say we wanted to call this function, "show_my_info". Here's how we'd create it:
The keyword "def" stands for "define," as that's what we're doing — defining a new function. But, just like with built-in functions, the computer won't run this code until the function is called.
After the first line that names the function comes the code that we want our function to run every time it is called. In this case, it's the two print lines we discussed earlier. Notice that all the code lines of the function are indented. This is required — just like with loops — so the code knows which lines are associated with which function.
To now use our function, we can call it elsewhere in our program, just like we do with built-in functions:
Let's put it all together and write a program that defines this function and then calls this function to actually have it print out those two lines:
As mentioned earlier, one big advantage of functions is that they allow us to reuse the same code over and over. So, let's see what happens when we call that function several times in a row:
If you run this program, you'll see that each of the three times the function is called, it prints the two lines. Imagine if we were going to need those two lines printed a hundred times throughout our program – you can see how using a function is a lot simpler and also makes our code much less complicated.
Note: We mentioned earlier that when you run a program, the computer will execute each line of code, starting at the top and moving down through the code, line-by-line. But, when the computer sees a function, it doesn't execute that code until the function is called. So, for our code above, the first three lines (the function definition and the two lines of code in the function) are ignored and the computer will start by executing the first line below the function. To make things simpler, we can even store custom functions in separate files, just like built-in functions!
Now that we have a basic idea of what a function is and how it works, let's talk about one of the more powerful aspects of using functions. Oftentimes, functions will contain code that we want to use over and over again, but we're going to want the code to do work slightly differently each time we use it.
For example, when your cell phone rings, the software inside your phone is doing a lot of complicated stuff to generate the ring. Your phone has to "wake up," turn on the back light, print information on the display, check to see if you're pushing any buttons, play a ringtone, etc. In fact, the code that makes your cell phone ring may contain a hundred or more lines of code.
When different friends call, you're going to see different information on your screen. For your friend John, you might see John's name, phone number and picture. For your friend Allison, you might see Allison's name, phone number and picture. Does this mean that the software has to have a hundred lines of code for John and a different hundred lines of code for Allison (as well as a different hundred lines of code every other person in your contact list)?
Luckily, no...
With functions, we have the ability to write generic tasks (like generate
a ring), while also changing based on specific information (like putting
different information on the screen for different callers). This is done by
sending "inputs" (also called "parameters") to the function. Parameters are
just pieces of information that the function uses to customize the task it is
performing. You saw that with built-in functions as well — remember
how we pass GPIOs in our Output()
and Button
functions:
Let's go back to our previous concept where we printed two pieces of information on the screen – my name (Jason) and the year I was born (1991). What if we wanted to print a name and birth year for other people as well – people with a different name and birth year than mine? To do this, we modify our function to receive parameters and to use those parameters to customize what the function does.
In this example, our function is going to take two parameters:
A name
A birth year
We tell the function what parameters to expect by listing them between the parentheses in the first line of the function (the line that names the function). Each parameter has its own name, which should be descriptive of what the parameter is.
For example, if we wanted to modify our function from the previous project to take a name and birth year parameters, it might look like this:
"name" and "birth_year" are now variables that we set when we call the function, and those variables can be used within that function:
Now, when we call the show_my_info function, we will always supply two parameters to the function – a name and a year.
For example, let's say we have a friend named Bob and he was born in 2005. We can send his information to the function like this:
Notice that we put quotation marks around "Bob" to make it a string (as you would expect), but we left the quotation marks off of 2005, making it a number instead of a string. While we could have put quotation marks around 2005 to make it a string, we've decided to make it a number for reasons that will become clear later on.
As another example, let's say we have a friend named Susie who was born in 1999, and we want to print her information as well:
Now, let's put it all together, and see what our code would look like if we had this new function and we called this function twice – once to print Bob's information and once to print Susie's information:
You may have noticed that this example is very similar to our cell phone example above. The software in a cell phone likely handles a ring by calling a function – the parameters of this function would be all the information that the function needs to correctly display the caller's information on the screen and make the phone ring. So, the parameters that are likely passed to the function would include:
Name of caller
Phone number of caller
Picture to be displayed for that caller
Ring tone to be used for that caller
Etc.
As you might suspect, not only can functions take inputs, they can also send information back (return output) to other parts of the code. A good example of this is when we have a function that does some calculations for us, and we want to get the results of those calculations.
Perhaps instead of printing the name and birth year of people, we'd rather know how old the person will be on their birthday this year. Using the information we already have from our previous lesson, this calculation is pretty simple – we just subtract the birth year from the current year (2015 as of this writing) and we'll get the age they will be turning this year.
To create a new function to do this, we can still pass in the "birth_year" parameter for the person's birth year (like we did in the previous project) but, instead of printing the information, we do our age calculation and store the resulting value in a new variable called "age".
This is what the function would look like:
Note: When calling this function, it is required that the "birth_year" parameter is a number and not a string so that we can use it to perform this calculation.
Now, to send the information we've calculated back to the main program, we end the function with a return statement that contains the information we're sending back (in this case, we're sending the information contained in the variable, "age"):
The value of "age" would then be returned to where the function was called and that value could be stored in another variable, printed or used however it is needed.
For example, we could call this function for Bob and Susie like we did in the last project, but this time, we could get their age as well, store it in a variable and then print it out:
Here is what the entire program would look like: