So far, we have used several of Python's built-in functions such as input, print, range and sorted. Chapter 8 covers creating your own functions in Python along with different ways of storing them and pulling them into your program.
To see an explanation of all lecture material in chapter 8, watch: https://youtu.be/Ru21gUJWpuo
To see sample exercises that go with the Try It Yourself sections in the chapter, download: chapter_08.zip
A function is a block of code which only runs when it is called.
A function should be designed to perform one task (if you have a function performing multiple tasks, you should break it into additional functions)
Functions can return data and they can accept data known as parameters.
If you notice that you have the same lines of code in your program more than 1 time, you can pull them out and put them into a function.
Functions make programs easier to test and easier to maintain because the code is in one place instead of multiple locations.
The def keyword is used to create functions. Functions can include parameters and return values, but neither are required.
Function names should be description and entered in lowercase letters with underscores between words. It is helpful to others if you include comments in your function explaining what it does (comments should go directly below the function header which is the first line of the function)
1. Syntax with no parameters:
def function_name():
statement1
statement2
statementn
function_name is the name of the function
The parenthesis after the function name are required (even if they are empty)
A colon at the end of the line is required
All statements the function should execute need to be indented below the function name
Example with no parameters:
def copyright():
print("(C) NMC 2021")
2. Syntax with parameters:
def function_name(parameter1, parameter2, parameterN):
statement1
statement2
statementn
Parameters need commas between them
Example with parameters:
def square(number):
print(f"{number} squared is ", number*number)
3. Syntax with parameters and return values:
def function_name(parameter1, parameter2, parameterN):
statement1
statement2
statementn
return value
Python doesn't require that you specify a return data type, the only thing required is the return keyword followed by whatever it is you are returning.
Example:
def square(number):
return number * number
We have already "called" functions that are built into Python: len(), input(), print() and sorted() are all Python functions.
To call a function, you need to code the function name and pass required arguments within the parenthesis. If the function returns a value, you will also need an assignment statement.
The traditional method of calling functions involves using positional arguments where the position of the value matters because it affects how the data is brought into the function and used.
Python allows use of keyword arguments where you can use the parameter names from the function and you can assign them values creating a key=value pair.
We will take a look at both types of arguments and how to code them
Functions may or may not return a value. If they return a value, you will need an assignment statement; otherwise, you don not need an assignment statement.
Positional arguments require that you know what position to send the data in. For example, if the function requires name, age and cell# in that order, then that is how you have to pass the data when you call the function.
To use a function, you need to know:
When you create your own functions, this information should be apparent :)
When you are using builtin functions, quite often, you have to look up the function to determine how it is set up so you know the proper way to call it.
a) Call syntax without a return assignment statement
function_name(argument1, argument2, argumentN)
NOTE: You only need to include arguments if the function has required parameters.
Terminology Note: A parameter is a variable in the declaration of function. An argument is the actual value of this variable that gets passed to the function.
Example:
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet('hamster', 'harry')
describe_pet('dog', 'willie')
Sample Output
I have a hamster. My hamster's name is Harry. I have a dog. My dog's name is Willie.
If you pass the arguments in the wrong order, you will end up with strange output as shown below:
describe_pet('Lucy', 'Llama')
describe_pet('Frankie', 'Fish')
Sample Output:
I have a Lucy. My Lucy's name is Llama. I have a Frankie. My Frankie's name is Fish.
b) Syntax with a return assignment statement
variableName = function_name(argument1, argument2, argumentN)
Example:
def square(number):
return number * number
squaredNumber = square(3)
print("The number squared is ", squaredNumber)
#another way to call and use the square function is from the print statement
print("The number squared is ", square(3))
Sample Output (it is the same for both calls)
The number squared is 9 The number squared is 9
NOTE: You will only need an assignment statement if the function has a return statement and returns a value.
The main difference between keyword and positional arguments is that keyword use the parameter name and an assignment statement in the argument list which forms a "key". Python then matches up the "key" passed in the function call with the parameter name in the function header.
The advantage of using keyword arguments is the order of the arguments doesn't matter because it matches up arguments and parameters based on the keyword.
a) Call syntax without a return assignment statement
function_name(parameterName=argument, parameterName=argument, parameterName=argumentN)
Where parameterName must match up to the parameter variables in the function header.
Example from the book:
def describe_pet(pet_name, animal_type):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
#function call
describe_pet(pet_name='willie', animal_type='dog')
b) Syntax with a return assignment statement
variableName = function_name(parameterName=argument, parameterName=argument, parameterName=argumentN)
NOTE: The data type of the return variableName should match what the function is returning (if the function returns a list, the variable should be a list)
Example:
import random
def raised(number,power):
return number ** power
n1 = random.randrange(1,10)
n2 = random.randrange(1,3)
print(f"The number {n1} raised to the {n2} power is ", raised(number=n1,power=n2))
Sample Output:
The number 4 raised to the 2 power is 16
If you create a function with parameters, you can set them equal to default values which makes passing arguments optional (if you don't pass the argument, the variable in the function will use the default value). This can be done with positional or keyword parameters.
To create default values, you simply set the parameter in the function header equal to a value.
Example from the book that uses defaults with keywords (because animal_type has a default of dog, the only required parameter is pet_name)
def describe_pet(pet_name, animal_type='dog'):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
#function call that omits animal_type and uses the default
describe_pet(pet_name='willie')
#function call that includes animal_type and overrides the defaultdescribe_pet(pet_name='snowball',animal_type='cat' )
Sample Output:
I have a dog. My dog's name is Willie. I have a cat. My cat's name is Snowball.
Example #2 that returns a value:
import random
def raised(number,power=2):
return number ** power
n1 = random.randrange(1,10)
n2 = random.randrange(1,3)
#passes both numbers to the function
print(f"The number {n1} raised to the {n2} power is ", raised(number=n1,power=n2))
#uses the default for the power and only passes the number to be raised
n1 = random.randrange(1,10)
print(f"The number {n1} raised to the 2nd power is ", raised(number=n1))
Sample Output:
The number 9 raised to the 1 power is 9 The number 2 raised to the 2nd power is 4
Some key points to remember include:
1. What determines if arguments are positional or use keywords is the function call (not the function itself).
2. The function itself ONLY determines if an argument is required.
3. If the function parameter has a default value, it is NOT required.
4. If the function parameter doesn't have a default, it IS required
5. One function can be called using positional arguments or keyword arguments or a combination of both
6. You will get errors if you forget required arguments, miskey keywords or insert arguments in the wrong order for positional argument calls (sometimes if you put arguments in the wrong order, you just get weird results rather than errors)
The example below shows a function with default values and function calls that include positional and keyword arguments:
Sample Output:
You worked 16 hours at an hourly rate of 20 and your gross pay is 320 You created 347 pieces at a piecerate of 3, your gross pay is 1041 You worked 12 hours at an hourly rate of 15 and your gross pay is 180
To see a video explanation, watch: https://youtu.be/DrRTMNM8yjw
1. Open the CIT228 folder and create a new folder named Chapter8
2. Create a new file and call it shirt_factory.py (save the file into your Chapter8 folder)
3. Using the shirt_factory.py file, complete Try It Yourself 8-3 and then modify the program for Try It Yourself 8-4 (page 137)
Sample Output:
Your shirt is size medium with the message 'I love Python' printed on the front.
Your shirt is size large with the message 'I love Python' printed on the front.
Your shirt is size small with the message 'In a world where you can be anything, be kind' printed on the front.
4. Save all your changes.
Functions can return any type of data including lists and dictionaries. Since Python is loosely typed, you just need to assign a variable to the data returned by the function.
Example of a function returning a dictionary
Sample Output:
Client #1: {'age': 29, 'weight': 120, 'height': 67, 'bmi': 18.792604143461794, 'status': 'normal'}
Client #2: {'age': 45, 'weight': 160, 'height': 70, 'bmi': 22.955102040816328, 'status': 'normal'}
Client #3: {'age': 65, 'weight': 140, 'height': 60, 'bmi': 27.33888888888889, 'status': 'overweight'}
Example of the same function in a while loop with the dictionary item being added to a list:
Sample Output:
How many clients are you entering?3
Enter the clients weight: 120
Enter the clients height in inches: 64
Enter the clients age: 58
Client # 1 's health information: {'age': 58, 'weight': 120, 'height': 64, 'bmi': 20.595703125, 'status': 'normal'}
Enter the clients weight: 150
Enter the clients height in inches: 67
Enter the clients age: 30
Client # 2 's health information: {'age': 30, 'weight': 150, 'height': 67, 'bmi': 23.490755179327245, 'status': 'normal'}
Enter the clients weight: 110
Enter the clients height in inches: 69
Enter the clients age: 21
Client # 3 's health information: {'age': 21, 'weight': 110, 'height': 69, 'bmi': 16.24238605335014, 'status': 'underweight'}
List of client dictionary entries: [{'age': 58, 'weight': 120, 'height': 64, 'bmi': 20.595703125, 'status': 'normal'}, {'age': 30, 'weight': 150, 'height': 67, 'bmi': 23.490755179327245, 'status': 'normal'}, {'age': 21, 'weight': 110, 'height': 69, 'bmi': 16.24238605335014, 'status': 'underweight'}]
All the processing you have learned so far applies to functions. The only thing you need to remember is to pass arguments and store values that are returned from the funciton.
Another example that uses a dictionary, list and while loop:
Sample Output:
How many clients are you entering?2
Enter the clients age: 45
Enter the resting heart rate or 50: 60
Client # 1 's training information: {'low': 57.5, 'high': 97.75, 'adjLow': 117.5, 'adjHigh': 157.75, 'message': 'Your training heart rate is between: 117.5 amd 157.75'}
Enter the clients age: 12
Enter the resting heart rate or 50: 50
Client # 2 's training information: {'low': 79.0, 'high': 134.29999999999998, 'adjLow': 129.0, 'adjHigh': 184.29999999999998, 'message': 'Your training heart rate is between: 129.0 amd 184.29999999999998'}
Example from the book using a while loop and break statements:
Sample Output:
Please tell me your name:
(enter 'q' at any time to quit)
First name: Scooby
Last name: Doo
Hello, Scooby Doo!
Please tell me your name:
(enter 'q' at any time to quit)
First name: Scrappy
Last name: Doo
Hello, Scrappy Doo!
Please tell me your name:
(enter 'q' at any time to quit)
First name: q
You can pass lists, dictionaries and other objects to functions as long as the function is coded to handle the complex data type.
Example from the book which passes lists to 2 different functions
Sample Output:
Printing model: dodecahedron
Printing model: robot pendant
Printing model: phone case
The following models have been printed:
dodecahedron
robot pendant
phone case
Weird Python Quirk: If you are modifying a list and removing items, you MUST do it in a while loop in order to process everything in your list. If you try removing items from a list when it is in a for loop, it will skip the item after the pop or remove command.
You may think the following for loop would work better than the while loop shown in the program above; however, after the first item is removed, the second item moves to the front of the list and Python thinks it has processed that item already which is why it gets skipped. This happens to every item after one is removed.
Revised Program:
Output showing that an item was skipped because of the for loop processing:
Printing model: phone case
Printing model: dodecahedron
The following models have been printed:
phone case
dodecahedron
Example that passes 2 lists to a function and updates current users with valid new users:
Sample Output:
List of current users before additions: ['scooby', 'shaggy', 'daphne', 'thelma', 'freddy']
Pebbles was available and has been assigned.
Wilma was available and has been assigned.
Betty was available and has been assigned.
Freddy has been taken, please use something else.
Barney was available and has been assigned.
List of current users after additions: ['scooby', 'shaggy', 'daphne', 'thelma', 'freddy', 'Pebbles', 'Wilma', 'Betty', 'Barney']
Example that passes 3 dictionaries to a function:
Sample Output:
Based on our survey, you are interested in the following travel destinations
Paris France
Madrid Spain
Rome Italy
Keys Florida
London United Kingdom
Based on our survey, you are interested in the following accomodations
Type = Airbnb
Length = 2 Weeks
Bedrooms = 3+
Bathrooms = 2+
Kitchen = Yes
WiFi = Yes
Laundry = Yes
Based on our survey, you are interested in the following method of transportation
Rental = Car
Size = 6 Passenger
Miles = Unlimited
If you do NOT want a function to modify a list, you can insert [:] after the argument in the function call. Doing this will NOT result in an error, even if the function was supposed to modify the list.
Syntax: function_name(argument[:], argument2, argumentN)
Example from the book shows that unprinted_designs and completed_models are supposed to be modified in the print_models function, but adding [:] after each list in the function call prevents that and the program still runs without errors:
print_models(unprinted_designs[:], completed_models[:])
Sample Output from the program (both functions ran fine, but the second one normally prints completed models and as you can see, it had nothing to print because the list wasn't updated in print_models):
Printing model: dodecahedron
Printing model: robot pendant
Printing model: phone case
The following models have been printed:
To see a video explanation, watch: https://youtu.be/QBvMmeOAzu0
1. Create a file named album.py and save it to the Chapter8 folder
2. Complete Try it Yourself 8-7 and 8-8 on page 142 IMPORTANT: For 8-8, the parameter for the number of songs should have a default value of 0 instead of none (track # of songs should be numeric).
3. Create a file named messages.py and save it to the Chapter8 folder.
4. Complete Try It Yourself 8-9, 8-10 and 8-11 on page 146
If you need to create a function and you are not sure of how many arguments the function call will pass, you can add an * before the parameter in the function header. The * indicates that an unknown number of arguments will be passed.
Example from the book - you should note that the function calls include a different number of arguments which is handled by the function because of the * before the parameter
def make_pizza(*toppings):
"""Print the list of toppings that have been requested."""
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
If you have a keyword argument and you are unsure of how many will be passed, you can place two * in front of the parameter name in the function header
Example from the book (slightly modified)
def build_profile(first, last, **user_info):
"""Build a dictionary containing everything we know about a user."""
user_info['first_name'] = first
user_info['last_name'] = last
return user_info
user_profile = build_profile('albert','einstein',location='princeton',field='physics')
print(user_profile)
user_profile = build_profile('scooby','doo', location='USA', occupation='Detective', hobbies='eating')
print(user_profile)
Sample Output:
{'location': 'princeton', 'field': 'physics', 'first_name': 'albert', 'last_name': 'einstein'}
{'location': 'USA', 'occupation': 'Detective', 'hobbies': 'eating', 'first_name': 'scooby', 'last_name': 'doo'}
NOTE that all the key=value pairs were included in user_info as key:value pairs automatically
If there are key=value arguments that are unrelated, it is often coded using **kwargs
Example of a function header using kwargs:
def user(name,**kwargs)
To see a video explanaton, watch: https://youtu.be/Y2jtmPGLVJM
1. Create a new file named sandwich.py
2. Complete Try It Yourself 8-12 on page 150
So far we have created functions that are at the top of the programs that use them.
We have also used the import random command which brought in a separate library file called a module. Bringing in modules allows you to call functions stored in the module within your own program code (this is what we did when we used random.randrange).
Python lets you place your own functions into external files (ie modules) and import them just like we did with the random module. This is considered to be a best practice.
Storing your functions in separate files has several benefits:
There are several methods of importing modules:
We will take a closer look at each one.
Import statements should appear at the top of your program (that is best practice). The only exception would be using comments at the beginning of the file to describe your program. In that case, immediately below the comments should be your import statements.
There are 2 ways to import the entire module.
Method 1 (which is what we have been using)
Syntax: import module_name
This method requires prefixing the function call with the module_name (that is how Python knows which functions to copy into your program)
Example importing a library module:
import random
If you use this method, you need to prefix any function call with the module name
Example using a library module:
random.randrange(1,100)
Where random is the name of the module and randrange is the name of the function
Example importing our own function which was stored in a heartrate.py file
Functions stored in module health.py
Program file trainingClients.py
Method 2 (new)
You can omit prefixing the function calls with the module name using this method.
Syntax: from module_name import *
It basically instructs python to copy everything from the module into your program, so you have ready access to ALL functions in that module. This is different from using import module_name because that method only imports what you are using from the module instead of everything.
Revised example of the trainingClients.py program
Which method is better?
If you believe your program may be modified to use additional functions in the future AND the module file is small, it may make sense to import everything; otherwise, I would import only what I need to use
You can be very specific with regards to importing in Python.
If the file you are importing from is large, it may be faster to specify a specific function within the module instead of the the entire module itself.
This also makes sense if you are only going to use one function.
Syntax: from module_name import function_name1, function_name2, function_nameN
The main benefits from importing this way are:
1. You only import what you are going to use
2. You don't need to prefix the function_name with the module_name
Revised example of the trainingClients.py program
If the function name you are importing conflicts with a name in your program, you can give it an alias and use the alias in your code.
Syntax: from module_name import function_name as alias
Example: from health import calc_rate as hr
Revised example using an alias function name
If a module name is lengthy, you can shorten it by giving it an alias.
Syntax: import module_name as alias
Example: import health as h
To see a video explanation, watch: https://youtu.be/e0rx0Lzw_wY
1. Complete Try It Yourself 8-15 on page 155 using the messages.py file.
a) You should name the file with the functions message_activity.py.
b) After you create the message_activity file, modify the messages.py file to import the functions as directed.
c) You will need to import the messages.activity module 5 different ways. You can comment out the import statements that you aren't using similar to the example in section D above
To see a video demonstration, watch: https://youtu.be/uB7MZxehmQg
1. You should have the following files in your Chapter8 folder:
2. Upload Chapter8 to GitHub
a. Click the ... next to CIT228 Git and select the Changes menu, Stage all Changes command.
b. In the Message window below Source Control, enter Chapter8 and then click the ... next to CIT228 Git and select the Commit menu, Commit Staged command
c. Display the menu next to the CIT228 Git folder by selecting ... and select the Push command
d. This will put all files and folders inside your CIT228/Chapter8 directory into your GitHub repository
3. Open a web browser and go to your CIT228 repository. Make sure the Chapter8 directory and files are there, then copy the URL and paste it into the lab assignment dropbox (you are done with the second part of your lab assignment!)