Join Barron Stone for an in-depth discussion in this video Code reuse, part of Programming Foundations: Real-World Examples.
- Eating nothing but omelets would get old real quick. Variety is the spice of life so I should probably add another function to my menu of breakfast recipes. - How about making some pancakes? - Sounds good to me. To make a pancake, I start by mixing together the ingredients in a bowl. Then I pour that mixture into a frying pan, I cook the pancake on one side, flip it, I cook the other side, and the output of that process, is a delicious pancake. Hmm, something seems familiar about this. Ah, the process for making a pancake has a lot in common with the process for making an omelet.
Performing the same steps in multiple places is the perfect time to consider functionalizing that process. Back in idle I had the start a 102 breakfast function scripts open which has a new function for making pancakes. Inside of the make pancake function, I perform all of the steps in the pancake making process. I mix the ingredients, pour the mixture into a frying pan, cook the first side, flip it, and cook the other side. At the end, the make pancake function returns a string object which represents a delicious pancake. It's pretty easy to see that the make omelet function and the make pancake function have a very similar structure.
In fact, both of these functions use the exact same sequence of cooking steps in the middle. That makes sense because both of these dishes involve cooking a flat thing in a frying pan. And since I'm doing the exact same series of actions in two places, I should combine those steps into a single function. So, I'll create a new function at the top of my script called mix and cook. And I'll copy and paste that sequence of steps that the make omelet and make pancake function have in common. It's important that I create the mix and cook function above the other two functions in the script.
I need to define the mix and cook function before I can use it in the make omelet and make pancake functions below it. You may also have noticed that I did not include a return statement at the end of the mix and cook function. Not all functions have to return a value when they finish like how the make omelet and make pancake functions return strings. Since I did not specify a return value for the mix and cook function, after the function executes its last instruction, cooking the other side, it will automatically return without passing back any output values.
Imagine this as Python inserting an invisible statement that says, return none at the end of the function. Now that I defined the mix and cook function, I'll replace those steps in the other two functions with a single call to mix and cook. Now, when I execute make omelet it will call the mix and cook function to perform those steps. And the same thing will happen when I execute make pancake. So I'll save those changes, and run the script. I'll switch over to the interactive shell, and let's try and make it a pancake by calling the make pancake function.
As expected, it performs all of the steps for mixing, cooking, and flipping, and finally returns a delicious pancake. Similarly, if I try making an omelet, by using the make omelet function, it performs all of the necessary steps and I get back a tasty omelet. Now, the question to consider is why was it useful to put those cooking steps into a new function. Simply put, code reuse. I can easily reuse that mix and cook routine to create more functions for cooking other recipes that also involve mixing and cooking things in a frying pan.
For example, if I wanted to create a new function that makes crepes, it would be fairly trivial to do so because I can reuse the mix and cook routine. A secondary benefit I get from combining those common steps into a single function is that if I need to make a modification to the process, I only need to do it in one place. Let's say down the road I realize that the reason I'm having so much trouble flipping my omelets and pancakes is because I forgot to grease the pan first. To fix that, I only need to add a step for greasing the pan in one place, the mix and cook function.
I'll do that now by inserting a new print statement, for greasing the frying pan. Now when I save and run the script, when I got to make an omelet, the process will include the new step of greasing the frying pan. And similarly, if I make another pancake, then you'll see that now that process also includes greasing the pan. If I had not combined those steps into the mix and cook function, then when I realize that I needed to add a step to my process for greasing the pan I would have had to add it to all of my cooking functions individually.
When I only have two functions for making omelets and making pancakes that's not such a big deal, but as I expand my library of functions to include tens or hundreds of recipes, then it becomes a real challenge to track down all of the places that I need to make that change and there's a pretty good chance I'll make a mistake in the process.
- Reusing functions
- Local vs. global variables
- Creating and naming custom objects
- Class inheritance
- Modules and packages
- Multidimensional lists and tuples
- Queues and stacks
- Creating and combining sets
- Storing data in dictionaries
- If/else and switch statements
- For vs. while loops
- Error handling
- Polling and event-driven programming