Chapter 9, Lesson 2 Text
Lesson Two: Function Inputs and Outputs
Many functions require some type of input data. When you call print(), for example, you pass in a string and possibly other parameters that will be combined in the output to the screen. Functions may also return some output data that can be used for other purposes. You have used the str.format() function to produce a string and the random.randrange() function to generate an integer. In this lesson, you are going to learn how to expand your own functions to accept input parameters and return output data.
Required (Positional) Parameters
If your function wants to receive input data, those data values should be identified by names that are listed inside the parentheses in the function "def" statement. You can list any number of names inside the parentheses; each represents a data value that must be passed into the function.
def <function name>(<param name 1>, <param name 2>, <etc...>):
Each parameter name acts like a variable within the function. The named parameters hold data and can be used in expressions and assignment statements just like any other variable! These parameters are how your function receives and processes data.
The illustration below shows the function greet() with two parameters, name and town, defined inside the parentheses.
When these parameters are present, every time the greet() function is called, two input values must be provided in the function call. We have shown greet() being called with "Rudy" as the first value and "Chicago" as the second value. The first value is automatically stored in the first parameter (name) and the second value is stored in the second parameter (town). We can then use name and town inside the function body as regular variables that hold data.
This automatic storage of input values in function parameters based on their positions in the list is very common. If you accidentally swap the input values, calling greet("Chicago","Rudy") instead, then "Chicago" would be stored in the name parameter and "Rudy" would be stored in the town - even if it doesn't make much sense! It's up to youas the programmer to ensure that you pass in the required parameters in the correct order, as defined by the function.
The code below uses our greet() function example with two input parameters. Try running it to confirm the expected output. You can change the input values and watch how the output changes to match.
Try It Now
As you can see, inside the greet() function, the name and town variables are used just like any other standard variables.
It is possible to let programs call a function without providing all of the required data. Instead, you can assign a default value to a parameter in your function definition. That way, if the function call does not provide data for that parameter, the default will be automatically assigned instead.
To define default values for parameters in your own function, simply enhance the "def" statement to set parameters equal to some default value. The example below assigns the default value "Atlanta" to the town variable in the greet() function.
def greet(name, town = "Atlanta"):
Now, when someone calls the greet() function, they can choose to pass in just the name, or to provide both nameand town. If a value for town is missing, "Atlanta" will be automatically assigned instead. Run the code below to see default parameters in action!
Try It Now
You may want to call a function and specify just one among a number of optional parameters. Or, you may not remember the right order of the positional parameters. Fortunately, in Python, you can make function calls and provide the name of the parameter directly in the call! That way, you are sure that a particular value goes to a specific parameter, even if you've gotten things out of order.
To use named parameters, you don't need to do anything special in your function "def" statement. Python automatically allows anyone calling a function to use named parameters. In the example below, all three function calls to greet() will do the same thing. In cases where we pass in named "town" and "name" parameters, the order doesn't matter because each is specifically assigned to a parameter by name.
greet(town="Philadelphia", name="Betsy Ross") # use named parameters in any order greet(name="Betsy Ross", town="Philadelphia") # use named parameters in any order greet("Betsy Ross","Philadelphia") # rely on positional order
Here is a full example that demonstrates both optional and named parameters. Can you predict the output from each call to greet()? Try it and see!
Try It Now
Often, functions are built to return some useful data to the calling program. The data might be a simple number, string or Boolean value, or it could be a list, tuple or more complex object. When your function wants to send data back to the calling program, it will use the return keyword.
When you use return on a line by itself with no other expression, then nothing will be returned from the function. The program flow simply transfers back to the calling location.
return # send nothing back
However, if you add a value or expression after return, that value or the results of the expression will be sent back to the calling function! The example below show how to return a fixed value, the contents of a variable, or the results of a longer expression.
return 1.0 # send back the number 1.0 return results # send back the value stored in the "results" variable return results + 1.0 # send back the value calculated from the expression "results + 1.0"
You can actually use more than one return statement inside a function. As your logic flows through the function, the first time it hits any return statement, the function will end and any output data is sent back immediately to the calling code. The remaining lines in the function body are skipped.
Carefully examine the calculate_grade() function in the example below. Notice that as soon as we identify a grade within the "if / elif / else" logic, we return that letter grade immediately. Can you see any path through the code where the "Never" value might be returned? It should not be possible to reach that statement because every path through the earlier logic results in a return. Try running the code with different input values and watch the results.
Try It Now
When calling a function that returns a data value, your calling code basically has three choices:
- Ignore the value completely, and it will be discarded
- Store the value in a variable for later use
- Use the value immediately in some other expression or statement
The three examples below demonstrate each of these approaches.
calculate_grade(85) # ignore the return data grade = calculate_grade(85) # store the return data for later use print("Your letter grade is: ",calculate_grade(85)) # use the return data immediately
Usually, when a function returns some data, you'll want to use that data in some fashion. But the exact approach is up to you and the needs of your program!
Work with Me: Getting the Day of the Week
Let's put your new function input and output skills to work. In this exercise, you are going to write a get_day_of_week() function, which will accept an input date in the format "YYYY-MM-DD" and return a string containing the day of the week (like "Monday"). You are going to use features of the datetimelibrary that you've already learned, so you may want to review those functions.
Here are some example function calls and the resulting output.
# main code starts here print(get_day_of_week("1776-07-04")) # US Declaration of Independence adopted print(get_day_of_week("1918-11-11")) # World War I Armistice Day print(get_day_of_week("3-16-2001")) # Test invalid date format
When run, you should see the following output. Notice that the function will handle invalid input (a date in the wrong format) with a nice error message instead of throwing an exception and crashing.Thursday Monday Invalid YYYY-MM-DD Date
The starting code below imports the datetime library for you, and it already contains the main code that calls get_day_of_week() several times. The results are printed directly to the screen. It's up to you to write the full get_day_of_week() function by completing the following steps.
- Near the top of the code, after the import statement and before the main code, add the "def" statement for get_day_of_week(). The function should accept one input parameter named target.
- Next, start an exception-handling block with "try". It is possible that the input string is not in the right format, and we want our function to cleanly handle that situation without crashing. Inside the try block:
- Create a variable named thisDate and set it equal to the results of parsing the target input string using datetime.datetime.strptime(). The format string should be "%Y-%m-%d" to handle input in the "YYYY-MM-DD" format.
- Create a variable named dayOfWeek and set it equal to calling strftime() on thisDate. The format string should be "%A", which will format the day of the week like "Monday".
- "return" the dayOfWeek value to the calling code.
- Add an "except" statement to mark the exception-handling block. Statements in this block will run if the strptime() function receives unexpected input and throws an exception. Inside the "except" block:
- "return" the hard-coded value "Invalid YYYY-MM-DD Date"
Try It Nowimport datetime# define the get_day_of_week() function here# main code starts hereprint(get_day_of_week("1776-07-04")) # US Declaration of Independence adoptedprint(get_day_of_week("1918-11-11")) # World War I Armistice Dayprint(get_day_of_week("3-16-2001")) # Test invalid date format
When done, test your code and make sure it produces the expected results. You should also test today's date as input and verify that you get the right day of the week for today. It's always a good idea to test your code with known inputs and outputs to make sure everything is working correctly.