Chapter 3. Evaluating Python Functions
In Chapter 2 - Defining Python Functions you learned how to define functions and some best practices for the functions. As you may have deduced already, there is not a single right way to program. You can make lots of decisions such as what to name your variables, how to split up sub-processes, and how much of an equation to put on a single line. Even though there are lots of ways to write a function, there are definitely better written functions and worse written functions. In chapter 3 you will learn how to look at a function and be able to interpret, analyze, and criticize Python functions.
By the end of the chapter you should be able to:
- read a function and explain its actions
- read a function and predict its results
- compare the actions of two different functions
- identify bad practices in a function
What will this function do?
Now that you know how to define functions, you need to be able to read and interpret a complete function. If the programmer gave the function a description function name, finding out what the function does should be obvious. However, it is important to be able to look into the code of a function to see if the function does what you expect. Take a look at Function 3.1 and see if you can give it an appropriate function name.
def _______________ (pennies, nickels, dimes):
penny_total = pennies
nickel_total = nickels * 5
dime_total = dimes * 10
total = penny_total + nickel_total + dime_total
return total
- Look at the inputs
- Look at each line and figure out what it does
- Look at what the function returns
It is perfectly acceptable if you feel you do not know where to start. The best place to start is to look at the inputs. You notice that there are three inputs pennies, nickels, dimes. These likely represent the number of each that are being passed to the function. Next you can look at each line one at a time. The second line does not appear to do anything except assign a new variable name to whatever value is in pennies. The third line multiplies the number of nickels by 5. This looks like the line is getting to total value of all of the nickels. The fourth line confirms this by multiplying dimes by 10. The fifth line adds the three totals from the previous lines. The sixth line returns the total. Therefore, this function appears to calculate the value from pennies, nickels, and dimes. If we apply the best practice of using descriptive function names, we could use:
calculate_value_of_pennies_nickels_and_dimes
Predicting the results of functions
Now that you can read a function, you need to be able to predict what the results will be given specific inputs. For this we are going to modify Function 3.1 to include some default inputs. Default inputs are used to specify the value of a variable if one is not given. In Function 3.2 we have added a default value for each of the inputs. We have set pennies equal to 5, nickels equal to 3, and dimes equal to 1. Try solving what the function will return given the default values before continuing to read.
def calculate_value_of_pennies_nickels_and_dimes (pennies = 5, nickels = 3, dimes = 1):
penny_total = pennies
nickel_total = nickels * 5
dime_total = dimes * 10
total = penny_total + nickel_total + dime_total
return total
Now that we know the values for pennies, nickels, and dimes, we can work out the function line-by-line. The second line (penny_total = pennies) sets penny_total to 5 as that is the value of the input pennies. The third line sets nickel_total to 3 times 5 (the value of the input nickels * 5) or 15. The fourth line sets dime_total to 1 times 10. The fifth line adds up the three total variables to equal 5 + 15 + 10 that equals 30. Thus, the sixth line will return 30.
Comparing the actions of two different functions
Being able to compare the actions of two different functions is really just an application of what you have already learned. You need to be able to read and understand a function and be able to give them each a name. The best way to practice is to be given two functions and a single function name and be able to tell to which function the function name belongs. Thus, here is the function name: calculate_area. Functions 3.3 and 3.4 show two different functions without their name. Can you tell which one should be named calculate_area?
def ___________________ (width, height):
perimeter = 2 * width + 2 * height
return perimeter
def ___________________ (width, height):
area = width * height
return area
This is a fairly easy problem as one of the functions returns area and the other function returns perimeter. Therefore, Function 3.4 is more likely to be the correct function. However, as a double check the second line of each function calculates something. In this case, Function 3.4 multiplies the width and the height which is the correct way to calculate area. Therefore, Function 3.4 should have the function name: calculate_area.
Identify bad practices in a function
You have learned how to read and compare functions. The next thing you want to practice is to be able to look at a poorly written function and be able to identify bad practices and fix the function. Take a look at Function 3.5 and see if you can identify the errors. Also, before continuing beyond the function, try to rewrite the function to use better practices.
def thefunction (tablespoons):
c = tablespoons / 2 / 8
return c
Can you even figure out what Function 3.5 does? Whether you could or not did you identify any of the bad practices? The first one is that thefunction is not a descriptive nor does it use underscores between the words. This makes the name hard to read and makes it difficult to identify the purpose of the function. The correct name for this function should be convert_tablespoons_to_cups. Does that help you read the function? The second bad practice is the use of a non-descriptive variable name in the second line c. If we replace that with cups, it makes the code easier to read. We can now see that that we are transforming tablespoons to cups. Third, we have to wonder about the purpose of the 2 and the 8. If we split up these variables into two lines and see that we are first calculating ounces and then tablespoons. You can take this a step further and split Function 3.5 into two functions just in case you need to convert tablespoons into ounces and/or ounces into cups. Splitting the Function 3.5 into two functions helps to follow the single purpose best practice. Function 3.5 can be rewritten into Function 3.6 and Function 3.7.
def convert_tablespoons_to_ounces (tablespoons):
ounces = tablespoons / 2
return tablespoons
def convert_ounces_to_cups (ounces):
cups = ounces / 8
return cups
Practice
def _____________________ (current_month):
months_remaining_in_year = (12 - current_month)
percentage_of_year_remaining = months_remaining_year / 12
return percentage_of_year_remaining
def convert_cups_to_gallons (cups = 64):
gallons = cups / 32
return gallons
calculate_perimeter
def ____________________ (width, height):
area = width * height
return area
def ____________________ (width, height):
perimeter = 2 * width + 2 * height
return perimeter
def obscured_function_name (height, weight):
obscured_variable = height * weight
return obscured_variable
def hidden_function_name (height, weight):
hidden_variable = height / weight
return hidden_variable
def calculate_rotations_per_minute (rotations_per_second):
r = rotations_per_second / 60
return r
Answers to practice problems
- calculate_percentage_of_year_remaining
- 2
- the second function
- the second function
- undescriptive variable name