So far, our programs have contained all of their code in one overall block in one Python (.py) file. That's ok when programs are small, however as programming problems grow more complex, trying to manage hundreds or thousands of lines of code in one large block becomes challenging. Also, larger programs tend to have segments that are repeated unnecessarily. One way we can improve this is through writing functions.
We can visualize the difference between the programs we've been writing with all of the code in one place, versus programs that are made more modular by writing and using functions:
Program with one block of code
Program with modular functions
Page Menu:
Concept: Functions
Self-contained blocks of code (sometimes called modules) that perform specific tasks. Functions are very useful, particularly when the task they perform is needed frequently in a software system. Most programming languages, such as Python, have built-in functions available for programmers to use. Also, programmers can write functions to create customized reusable functionality for their programs.
We have already used some functions, that is, some that are built into Python, such as print(), len(), etc. These are functions that contain code to perform a task, such as printing to the screen or returning the length of an object. We don't know how they work and don't need to know, we just learn how to use them and interact with them and that's it. We can write functions and use them just like we use any built-in functions.
Goals of Writing Functions
When writing functions there are specific goals we try to achieve, as outlined here:
Goal
Description
Abstraction
In programming, we hide, or abstract, the details and implementation of programming tasks inside of functions. In doing so, programmers can use functions to the benefit of their programming tasks, without the need to fully understand all of the details of the implementation of those functions.
Modularity
As depicted in the image above, rather than a single large block of code, functions allow us to modularize our code so that related functionality is kept together. In addition, modularity can dramatically improve the maintainability of the code.
Reusability
Well-designed functions can often be used throughout a software system and even across many systems. The ability to call a function from many points in a system, or multiple systems, is reusability.
Reduce Complexity
Again referring to the image above, the program comprised of one large block of code can be very difficult to maintain. Imagine a single Python file with 2 million lines of code. Its complexity would be very high and it would be difficult to maintain. Functions allow us to create building blocks that are individually much smaller and easier to maintain, thereby reducing complexity by consolidating functionality into those blocks. This approach allows programmers to focus on one task at a time.
Reduce Redundancy
A program with a single large block of code also suffers from redundancy. If a particular task is needed many times throughout that large program, the code to accomplish that task is often repeated many times. By moving that task into a function, the implementation code is only needed once, and then that function can be called as many times as needed throughout the program.
Testability
Testing a single large block of code can be very difficult because of the complexity and scope of the number of lines of code. If a system is modularized with functions, each function can be tested individually and any problems mitigated in that function without affecting other code in the system.
Team Development
As software systems grow in size, development is often spread out across many programmers rather than relying on one person. Functions are very beneficial in team development because programmers can each focus on their functions in the system. In this kind of development environment, communication is very important so that everyone on the team is aware of the joint development efforts.
Code Sharing
In addition to the goals and features of functions outlined above, functions can also be shared with other developers within a company or across the world. Python is widely supported by many developers across the world and its core development, as well as the development of functions, are encouraged for sharing across the Python community.
Types of Functions
In Python, there are different types of functions. As mentioned above, Python has built-in functions that are available for our use that provide many features to simplify our programming tasks. We can call these functions from anywhere in our code. Calling a function means instructing the computer to run (execute) that function. As Python programmers, in addition to using the built-in functions, we can also create Void and Value-Return Functions of our own to achieve the goals outlined above. These two types of functions provide different approaches to modular code.
Void Functions allow us to write code that performs a specific task and then terminates, with no return interaction between the Void Function and calling program. An example of a void function might be a function that prints a standardized header at the top of all output for a program. Calling that function would cause the header to print, and there is nothing to return to the calling program.
Value-Return Functions allow us to write code that accepts values (arguments), performs actions on those values, and can return resulting values to the calling program. An example of a value-return function might be a function that calculates employee bonuses based on a set of values our calling program passes to the function, the function performs the calculations based on business rules and then returns a result (the bonus amount) to the calling program.
We will explore both Void Functions and Value-Return Functions throughout the rest of this page.
Coding Standards for Functions
There are some rules in Python for naming functions and also there are common conventions that are followed by many developers to improve consistency. The rules are similar to naming variables, for example, function names cannot include spaces, the first character of the name must be an alphabetic letter or an underscore (_), the rest of the name of a function can only contain alphabetic characters, digits 0 thru 9 or underscores, function names are case-sensitive and you cannot name functions the same as any Python keyword.
Common conventions for naming functions, like variables, suggests using descriptive names that relate to the purpose of the function. For example, naming a function x, while valid from the rules perspective, is not descriptive. Instead, use a name that helps the reader identify the purpose of the function, like print_header, calculate_interest, update_tax_record, etc.
Creating & Calling a Void Function
Creating a Void Function
The general form for creating a Void Function is as follows:
Code Line 1: The def keyword indicates the definition of a function.
The function_name must follow the coding conventions outlined above.
Function names must include parenthesis ( ) at the end of the function name.
Calling programs can pass values (arguments) to a Void Function. When a Void Function can receive arguments, we list variables inside the parentheses of the function signature as placeholders for those values. Inside the function, those variables become local variables the function can use for its tasks.
Function signature lines must end with a colon to indicate the end of the function name definition.
Code Lines 2 thru 6: Void Functions can contain any number of Python code statements.
There are return values in Void Functions.
Calling a Void Function
The general form for calling a Void Function is as follows:
function_name()
Code Details:
Code Line 1: To call a Void Function simply uses its name with empty parentheses.
Concept: Arguments & Parameters
These two terms are often used interchangeably, however, they are not the same. Arguments are the values we pass to a function, while parameters are the values received by the function. The confusion is often caused by the thought that the value is the same number, string, etc. But, we use the two terms to differentiate the perspective we have for the coding of either the calling program code or the coding of the function.
Example 1
In this example, we write a function to print a report header. This is a simple example of a Void Function that we could use any number of times in a program without the need to write the code for the header more than once. It is also a good example of how to make something that will remain consistent, that is, it will always print the same header information in the same format.
# Functions
def print_header():
print("\n" + "-" * 80)
print("S u m m a r y R e p o r t")
print("\n" + "-" * 80)
# Main (calling) Program
print_header()
Output
----------------------------------------
S u m m a r y R e p o r t
----------------------------------------
Functions create modular units of code separate from the main program, as depicted in the diagram below. The print_header() function is called from the main program, its code is executed, and program flow returns to the main program on the next line after the print_header() function call.
Code & Output Details:
Code Line 2: Function definition (def) of a Void Function called print_header().
Code Lines 3 thru 5: Lines of code inside the Void Function.
Code Line 8: In the Main Program, the function is called by the function name and a set of parentheses.
Example 2
In this example, we write a flexible function that will print dashes to create a horizontal line. The number of dashes is flexible through the use of a parameter specified in the function signature, so the programmer can call this function and specify the number of dashes they want to be printed to the screen.
# Functions
def print_line(num_dashes):
print("-" * num_dashes)
# Main (calling) Program
print_line(10)
print_line(20)
print_line(40)
print_line(80)
Code Line 2: Function definition (def) of a Void Function called print_line, which also has a parameter (num_dashes).
Code Line 3: The only line of code inside the function. This line uses the value passed to the function to determine how many times to print the dash character to create a horizontal line.
Code Lines 6 thru 9: Demonstrate several calls to the print_line function. Note the different values passed to the function. From the perspective of the calling program, these values are called arguments while they are called parameters in the called function itself.
Example 3
This example is an enhancement of Example 2 above. This function also prints characters to the screen to make a horizontal line and the number of characters that are printed is based on a parameter provided by the calling program. The enhancement is that in addition to the number of character parameters, we've added a second parameter to allow the calling program to specify what character to print and how many times to print that character. Compare the code for this example and Example 2 to see how we have enhanced this function.
# Functions
def print_line(print_char, num_chars):
print(print_char * num_chars)
# Main (calling) Program
print_line("-", 10)
print_line("~", 20)
print_line(".", 40)
print_line("=", 80)
Code Line 2: Function definition (def) of a Void Function called print_line, which has two parametersprint_char and num_dashes.
Code Line 3: The only line of code inside the function. This line uses the two-parameter values passed to the function to determine what character to print and how many times to print it to create a horizontal line.
Code Lines 6 thru 9: Demonstrate several calls to the print_line function. Note the different values passed to the function.
Example 4
This example combines our print header and print lines functions above to demonstrate that we can call functions, not only from main programs but also from other functions. This means functions can call functions. In this example, our main program calls the print_header() function, which in turn calls the print_line() function. This is a good example of the use of functions, that is, it demonstrates that many functions each doing their tasks can be combined to complete more complex work. This concept is very widely used in software development.
# Functions
def print_line(print_char, num_chars):
print(print_char * num_chars)
def print_header():
print()
print_line("-", 40)
print("S u m m a r y R e p o r t")
print_line("-", 40)
print()
# Main (calling) Program
print_header()
Output
----------------------------------------
S u m m a r y R e p o r t
----------------------------------------
Functions can be called from the main program or any other function as well, as shown in this example:
Code & Output Details:
Code Line 2: Function definition (def) of a Void Function called print_line, which has two parametersprint_char and num_dashes.
Code Line 3: The only line of code inside the function. This line uses the two-parameter values passed to the function to determine what character to print and how many times to print it to create a horizontal line.
Code Line 5: Function definition (def) of a Void Function called print_header, which has no parameters.
Code Lines 6 thru 10: This is the same function as shown in Example 1 above, however this time it uses the print_line function to produce the lines of the report header. This demonstrates functions calling other functions.
Code Line 13: Demonstrates calling the print_header() function from the main program. Notice that in this program example the print_line function is never called by the main program.
Creating & Calling a Value Function
Creating a Value Function
The general form for creating a Value Function is as follows. Notice that it looks the same as the Void Function with the addition of a return statement.
Code Line 1: The def keyword indicates the definition of a function.
The function_name must follow the coding conventions outlined above.
Function names must include parenthesis ( ) at the end of the function name.
Calling programs can pass optional values (arguments) to a Void Function. When a Void Function can receive arguments, we list variables inside the parentheses of the function signature as placeholders for those values. Inside the function, those variables become local variables the function can use for its tasks.
Function signature lines must end with a colon to indicate the end of the function name definition.
Code Lines 2 thru 6: Void Functions can contain any number of Python code statements.
Value Functions include a return statement, which returns some result that is arrived at inside the function.
Calling a Value Function
Here are a couple of examples of general forms for calling a Value Function:
Code Line 1: Calling a Value Function is similar to calling a Void Function, however since a Value Function will return a value to the calling program we need to capture that return value. Most commonly we do this by setting a variable equal to the function call. When the function finishes and returns a value, that value is stored in the variable. We can then use that variable as needed.
Code Line 1: This is an example of calling a Value Function inside of a print statement. Since a Value Function returns a value, we can place the call in a print statement and the function return value will be printed the same as if it were a local variable or literal value.
Example 1
In this example, we write a Value Function to calculate a simple math formula. This is an example of a Value Function that we could use any number of times in a program without the need to write the code for the calculation more than once. The function will return the result of the calculation to the calling program which we can then use as needed.
# Function
def calc_formula(n):
# Formula: n * n**3
ret_value = n * n**3
return ret_value
# Main (calling) Program
formula_value = calc_formula(4)
print("The result of the formula "
"calculation is " + str(formula_value))
print("We could have put the function "
"call directly in a print statement "
"like this: " + str(calc_formula(4)))
Output
The result of the formula calculation is 256
We could have put the function call directly in a print statement like this: 256
Code & Output Details:
Code Line 2: Function definition (def) of a Value Function called calc_formula().
Code Lines 3 thru 5: Lines of code inside the Void Function.
Code Line 8: In the Main Program, the function is called by the function name with an argument inside the function's set of parentheses. In this example, the argument is a literal value, but it could be a variable or expression.
The value passed to the function is used in the calculation and the return statement returns the result to the calling program.
Example 2
In this example, we combine three Value Functions that work together to format several strings together and return a single formatted string to the calling program. Notice that the three functions are format_phone(), print_line() and customer_card(). The customer_card() function is the primary function and the only one called from the main program. The other two functions are called by the customer_card() function.
See the Execution Flow section below for more information about how the execution of this program works. Also, work through the Code & Output Details below for a line-by-line explanation of the program and its output.
Enter your first name: Bob
Enter customer last name: Smith
Enter customer Address Line 1: 1234 Nowhere Street
Enter customer Address Line 2: Apt 9999999999
Enter customer City: Noplace
Enter customer State: UT
Enter customer Zip Code: 84999
Enter customer phone number (digits only): 1112223333
----------------------------------------
Bob Smith
1234 Nowhere Street
Apt 9999999999
Noplace, UT 84999
(111)222-3333
----------------------------------------
Code & Output Details:
Code Lines 2 thru 8:
Code Line 2: Defines a Value Function with one parameter (phone_no), which is expected to be in the form of 10 digits of a standard U.S. phone number (like 9999999999). These parameters are used inside the function to format those digits into the standardized phone format of (999)999-9999.
Code Line 3: We set a return value variable to hold the formatted phone number.
Code Line 4: This is a simplified example validation of the phone number parameter. In a full implementation, we would want to expand the validation to ensure all of the digits are numeric and that the phone number is valid in terms of the telephone industry standards.
Code Line 5: This is an example of how we might handle invalid phone numbers, that is, set our return value variable to a message indicating the number is not valid.
Code Line 6 & 7: The else: portion of our decision statement is where we convert the validated phone number parameter and use slicing to format the phone number.
Code Line 8: We use the return statement to return our return value variable.
Code Lines 11 & 12:
Code Line 11: Defines a Value Function with two parameters (print_char and num_chars), which are expected to be a character or string to repeat and a number to indicate how many times to repeat the specified character or string.
Code Line 12: We use the return statement to return a string created based on the two-parameter values. Note that this is similar but different from the print_line() function we've seen before that prints the line. In this example, this function creates the line and returns it as a string, instead of printing it. The calling function then uses it as needed, so printing of the line created in this function is left to the calling function to handle.
Code Lines 15 thru 25:
Code Line 15: Defines a Value Function with eight parameters (fn, ln, addr1, addr2, city, st, zip, phone), which are expected to be character strings. We will use these parameter values to create the customer card in the form:
-------------------------
FirstName LastName
Address Line 1
Address Line 2
City, State zip
(999)999-9999
-------------------------
Code Line 16: We set a return value variable (card) to hold the formatted card as one string (which will include \n sequences as well).
Code Line 17: This line starts to build the return value variable string. Note that this line calls the create_line function to get a line based on the specified character and number of characters.
Code Line 18: This line continues to build the card string by concatenating the first name (fn) and last name (ln) parameter variables to the card string. Note the use of the \n escape sequence that we include in the string so that when it is returned to the calling program it will be formatted as we want i
Code Line 19: Concatenates address line 1 to the card variable.
Code Line 20: This line is an example of how we might selectively use the parameter values that were passed to a function. In this example, not all addresses have a second address line, so we only want ot concatenate addr2 to the card if there is a value in that parameter variable.
Code Line 21: If there is content in the addr2 variable, then we concatenate it to the card variable.
Code Line 22: Concatenates the city, state, and zip code parameter variables onto the card variable.
Code Line 23: Calls the format_phone function passing the phone parameter variable to it. See the description of that function above.
Code Line 24: Calls the create_line function to get a line based on the specified character and number of characters.
Code Line 25: We use the return statement to return our card variable.
Code Lines 29 thru 38:
Code Lines 29 thru 36: These lines prompt the user for each of the customer data values.
Code Line 38: We use a print statement and call the customer_card() function and pass the 8 customer data values collected above as arguments.
Execution Path
As a reminder, execution path is the path through a program that the Python interpreter takes based on our code. So, for example, a program with just a set of print statements, with no decisions or loops, would be a straight execution path from line 1 through the last line of the program. As our programs become more complex, with decisions and loops, and now with functions, it can become increasingly challenging to understand the execution path.
The following list outlines the execution path of Example 2 above. Study the list of steps and the subsequent diagram of the code, along with the code, sample run, output, and code details provided above.
The execution path in the Example 2 program starts in the main program (labeled (1) in the diagram below). There are 8 input statements, one after another, which each executes in order from top to bottom.
Then, still in the main program, the print statement executes (2), which contains a call to the Value Function named customer_card(). That function call also passes the 8 variables that were created with the input statements above.
The execution path leaves the main program and is transferred to the customer_card() function (3).
Inside the customer_card() function, execution starts with the initialization of the variable card.
The next line calls the Value Function called create_line() and passes two arguments to it.
The execution path leaves the customer_card() function and is transferred to the create_line() function (4).
The create_line() function returns a string constructed based on the two parameters passed into the function().
The execution path leaves the create_line() function and returns to the customer_card() function.
The next 5 lines of the customer_card() function continue building the card string based on the parameters passed to it originally.
The next line calls the format_phone() function, which changes the format of the digits-only phone number from the parameter into a formatted version of the phone number string. The call to the format_phone() function includes the phone variable as an argument.
The execution path leaves the customer_card() function again, this time it is transferred to the format_phone() function.
The format_phone() function checks if the phone number is valid and if so, it formats the number using string slicing and concatenation.
The execution path leaves the format_phone() and returns to the customer_card() function.
The very next line in the customer_card() function calls the create_line() function again.
The execution path leaves the customer_card() function and is transferred to the create_line() function (4).
The create_line() function returns a string constructed based on the two parameters passed into the function().
The execution path leaves the create_line() function and returns to the customer_card() function.
The last line of the customer_card() is the return statement that returns execution to the calling program, the main program.
When the execution path returns to the main program, where we started, the print statement can complete by printing the card which is what was returned to the main program and the print statement. Since the card variable contains the result of the concatenations and function calls, the print statement can simply print it now.
The diagram below can be confusing at first, but if you follow the code details above while reading through the execution path steps above, the diagram depicts how the execution path operates in this example.
Practice Problems
Problem 1
Write a Python program that has a main program that prompts the user for their full name (store in one variable). Also, implement the print_line() Void Function is shown in the examples above. And write a new function that will print the user's name between two lines (see sample output below). Pass the user's name to the new function as a parameter. In the new function, call the print_line() function, then print the user's name and then call the print_line() function again.
Sample Run & Output:
Please enter your full name: Bob Smith
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Full Name: Bob Smith
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Python Code
# Functions
def print_line(print_char, num_chars):
print(print_char * num_chars)
def print_name(name):
print_line("~", 40)
print("Full Name: " + name)
print_line("~", 40)
# Main Program
full_name = input("Please enter your full name: ")
print_name(full_name)
Output:
Please enter your full name: Sally Samuelson
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Full Name: Sally Samuelson
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Solution Notes:
Code Line 13: In the first line of the main program, we declare a variable full_name and prompt the user for their full name.
Code Line 14: We then call our new function print_name() and pass the full_name variable to the new function.
Code Line 6: The definition of our new function print_name() and receives a parameter for the name.
Code Line 7: We call the print_line() to print a line based on the character and number of characters specified in our arguments.
Code Line 8: We print the user's name, based on the name parameter.
Code Line 9: We call the print_line() again to print a line below our name output.
Execution returns to the main program which then ends.
Problem 2
Write a Python program that calls a Void Function from inside of a for loop so that the function is used repeatedly. In the main program declare 3 variables, and use one as the index variable of a for loop. In each iteration, set the other two variables as multiples of the index value. Then call a function inside the loop and pass the three variables to that function. In the function print well-formatted output lines that shows what adding the three values together produces (see the sample output below).
# Functions
def calc(m, n, o):
print(str(m) + " + " + str(n) + " + " + str(o) + " = " + str(m + n + o))
# Main Program
i = j = k = 0
for i in range(20):
j = i * 2
k = i * 4
calc(i, j, k)
Code Line 6: Inside the main program, we declare three variables and initialize them to zero.
Code Line 7: We write a for loop using one of the variables as the loop index variable.
Code Lines 8 & 9: We set the other two variables to multiples of the first, these could be any value.
Code Line 10: We call our Void Function, passing the three variables as arguments.
Code Line 3: We define our function with three-parameter variables to hold the values passed from the main program.
Code line 4: Then we print the result of adding the numbers together.
After each iteration of the loop the process above repeats until we have reached the upper bound of the loop.
Once the upper range of our loop is reached the loop ends as does the program.
Problem 3
Write a Python program that prompts the user for two numbers and then displays the result of adding, subtracting, multiplying, and dividing those two numbers. Write this program with functions as follows:
Your main program should declare a list to store the user-entered values.
Your main program should call a Void Function to display user instructions.
Your main program should then call a Value Function that prompts the user for two numbers and return their entries as a list (store the return list in the list declared above).
Your main program should then call a Void Function to manage the calculations. Pass the list to this function.
The calculations function should call 4 individual Void Functions, one for each type of calculation as listed above.
The calculations function should pass the list to each of the 4 functions.
The 4 individual functions should calculate their value using the user-entered numbers in the list and print an output line indicating the result of the calculation.
All of the program's output should be well-formatted as shown below.
Sample Run & Output:
=============================================
This program asks you for two numbers
and then displays the results of adding,
subtracting, multiplying and dividing
those two numbers.
=============================================
Enter your first number: 2
Enter your second number: 4
=============================================
Results:
=============================================
2 + 4 = 6
2 - 4 = -2
2 * 4 = 8
2 / 4 = 0.5
=============================================
Thank you!
Python Code
# Functions
def print_line(print_char, num_chars):
print(print_char * num_chars)
def instructions():
print_line("=", 45)
print("This program asks you for two numbers\n"
"and then displays the results of adding,\n"
"subtracting, multiplying and dividing\n"
"those two numbers.")
print_line("=", 45)
def get_user_values():
# Tip: The lines below could be abbreviated like this...
# user_values = [int(input("Enter your first number: ")), int(input("Enter your second number: "))]
user_values = []
user_values.append(int(input("Enter your first number: ")))
user_values.append(int(input("Enter your second number: ")))
return user_values
def add_vals(vals):
print(str(vals[0]) + " + " + str(vals[1]) + " = " + str(vals[0] + vals[1]))
def sub_vals(vals):
print(str(vals[0]) + " - " + str(vals[1]) + " = " + str(vals[0] - vals[1]))
def mult_vals(vals):
print(str(vals[0]) + " * " + str(vals[1]) + " = " + str(vals[0] * vals[1]))
def div_vals(vals):
print(str(vals[0]) + " / " + str(vals[1]) + " = " + str(vals[0] / vals[1]))
def calculations(vals):
print_line("=", 45)
print("Results:")
print_line("=", 45)
add_vals(vals)
sub_vals(vals)
mult_vals(vals)
div_vals(vals)
print_line("=", 45)
# Main Program
values = []
instructions()
values = get_user_values()
calculations(values)
print("Thank you!")
Output:
=============================================
This program asks you for two numbers
and then displays the results of adding,
subtracting, multiplying and dividing
those two numbers.
=============================================
Enter your first number: 23
Enter your second number: 54
=============================================
Results:
=============================================
23 + 54 = 77
23 - 54 = -31
23 * 54 = 1242
23 / 54 = 0.42592592592592593
=============================================
Thank you!
Solution Notes:
Code Line 49: As specified in the problem description, we first declare a list that will hold the user-entered numbers.
Code Line 50: We call the instructions() Void Function that is on Code Lines 6 thru 12. This Void Function displays the user instructions and then execution returns to the main program.
Code Line 51: Next, we set our declared list equal to a call to the Value Function get_user_values(), on Code Lines 15 thru 19. That Value Function prompts the user values, stores them in a list and returns that list back to the main program. When execution returns to the main program the list returned by the get_user_values() function is stored in our values[] list.
Code Line 52: Lastly, we call the calculations() Void Function, which is on Code Lines 38 thru 46, and we pass the list containing the user entries to it.
The calculations() function calls the Void Functions add_vals(), sub_vals(), mult_vals(), and div_vals(). The calculations() function passes the user-entry list to each of these functions.
The add_vals() function uses the vals parameter (the list) to print a well-formatted result of adding the two user-supplied values.
The sub_vals() function uses the vals parameter (the list) to print a well-formatted result of subtracting the two user-supplied values.
The mult_vals() function uses the vals parameter (the list) to print a well-formatted result of multiplying the two user-supplied values.
The div_vals() function uses the vals parameter (the list) to print a well-formatted result of dividing the two user-supplied values.
After the calculations() function is finished calling the 4 math functions above, execution of the program returns to the main program where "Thank you" is printed and the program ends.