This tutorial was written by Katherine Walden and is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.
This lab provides an overview of foundational programming concepts in the areas of control flow and functions, with a focus on Python syntax. Topics covered include:
- Control flow and control structures
- Code modularity and reuse
- Built-in functions in Python
- Named functions in Python
- Core function components, including definition, arguments, parameters, scoping, and docstrings
|
Lecture/live coding playlist |
When building this lab, the author consulted materials developed by:
- Dr. Peter Bui for the CSE 10101 "Elements of Computing I" course.
- Dr. Janet Davis for the the CSC 105 "The Digital Age" course.
- Dr. Corey Pennycuff for the CSE 10101 Elements of Computing (Fall 2019).
- Lindsay K. Mattock for the the SLIS 5020 Computing Foundations course.
Definitions and explanations in this lab are adapted from Kenneth Leroy Busbee and Dave Braunschweig, Programming Fundamentals: A Modular Structured Approach, 2nd Edition (Rebus Press, 2018)
- Lecture & Live Coding
- Key Concepts
- Lab Notebook Template
- Overview
- Functions in Python
- Putting It All Together: Why Functions?
- How to submit this lab (and show your work)
- Lab Notebook Questions
Click here to access this lab procedure as a Jupyter Notebook.
Throughout this lab, you will see a Panopto icon at the start of select sections.
This icon indicates there is lecture/live coding asynchronous content that accompanies this section of the lab.
You can click the link in the figure caption to access these materials (ND users only).
Example:
|
Lecture/live coding playlist |
Click here for a full list of key concepts and definitions from this lab.
Click here to make a copy of the Replit template for this lab.
Alternatives:
.py
template (Google Drive, ND users)- Jupyter Notebook,
.ipynb
(Google Colab, ND users)
Moving forward, we'll submit lab notebooks as .py
files.
One option is to have a .py
file that you use to run code and test programs while working through the lab. When ready to submit the lab notebook, you add comments and remove extraneous materials.
Another option is to have an "official" .py
file that you are using as a lab notebook (separate from your working/testing file). Use comments in Python to note when you are starting a new question (as well as answering a question).
- Example:
Lab_Notebook_Walden.py
What gets submitted as the lab notebook is the Lab_Notebook_Walden.py
file.
- When in doubt, use comments
- Be sure you are using comments to note what question you're responding to
From Busbee and Braunschweig's "Structured Programming," in Programming Fundamentals:
"One of the most important concepts of programming is the ability to control a program so that different lines of code are executed or that some lines of code are executed many times. The mechanisms that allow us to control the flow of execution are called control structures. Flowcharting is a method of documenting (charting) the flow (or paths) that a program would execute. There are three main categories of control structures:"
- Sequence [executes in given sequence]
- Selection [selects between two or more flows using condition or question]
- Iteration [repeats same piece of code multiple times]
We're going to spend multiple labs thinking through control structures and control flow, with a focus on how we use them in Python.
Examples of control structures in Python include:
if-then-else
(syntax:if
,else
,elif
)while
statements (syntax:while
)
We've also previously been introduced to the concept of code blocks. From Busbee and Braunschweig's "Code Blocks" from Programming Fundamentals:
- "A code block, sometimes referred to as a compound statement, is a lexical structure of source code which is grouped together. Blocks consist of one or more declarations and statements. A programming language that permits the creation of blocks, including blocks nested within other blocks, is called a block-structured programming language. Blocks are fundamental to structured programming, where control structures are formed from blocks."
Approaching a program as a series of components that each accomplish tasks that are part of the larger workflow gets us to a new concept: modularity or modular programming
From Busbee and Braunschweig's "Modular Programming," in Programming Fundamentals:
- "Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality."
Code blocks are one way to think about these discrete parts of a program. A more precise term used in programming languages is function. "Functions are important because they allow us to take large complicated programs and to divide them into smaller manageable pieces. Because the function is a smaller piece of the overall program, we can concentrate on what we want it to do and test it to make sure it works properly" (Busbee and Braunschweig, Modular Programming).
|
Overview & Built-In Functions |
In Python, a function is a named sequence of statements that performs a computation.
- Key term: function
To execute a function, we call it by name and pass it an appropriate set of input arguments. A function takes zero or more arguments as inputs and returns zero or more outputs as a result. The output or result of a function is called the return value.
- Key terms: function call, input argument, function output or return value
Data, parameters, or arguments can be passed into a function. Functions can also return data.
We have actually already been working with a number of Python's built-in functions. These include print()
, dict()
, input()
, int()
, and len()
.
We call built-in functions using the function name, followed by parenthesis.
print()
dict()
input()
int()
len()
When we call one of these built-in functions, Python accesses and then executes the function's source code stored elsewhere in the Python environment.
- For example, you can see the source code for the
print()
function, contained in bltinmodule.c file in Python's source code.
Using print()
as an example:
- The function definition is contained elsewhere in Python's source code
- We call the function using its name
print()
- We pass some kind of input to the function (i.e.
print("Hello world")
) - Some functions have an output or return value
![]() |
Built-in Functions in Python Comprehension Check |
|
Named Functions |
But Python also lets us to create (and name) our own functions.
- Key term: named function(s)
We can define or name a function using the def
keyword. A function definition includes a few core components:
- The name of the new function
- The list of function arguments
- The sequence of statements to execute when the function is called
The core syntax for defining your own function:
# use def keyword to define function name
def function_name(argument):
statement(s)
return result
Let's unpack each of those components.
def function_name()
is the name you are giving to the function you create- this is the header for the function definition.- Function names have many of the same rules as variable names- no spaces or special characters.
argument
is the argument that will be passed to the function.- When we are initially defining the function, the
argument
value is typically a placeholder. - Later in the program when we call the named function, the argument being passed to the function goes in these parenthesis.
- When we are initially defining the function, the
- The nested or indented line
statement(s)
is the body of the function definition. It includes a sequence of statements to execute when the function is called. - The nested or indented line
return result
is a placeholder for the function output or endpoint- it is also part of the body of the function definition.
So what happens when we use the def
keyword to create a named function?
Programs are always executed sequentially, one statement at a time. Function definitions create new functions, but do not execute the bodies or statements within the functions UNTIL the functions are called.
When we call a named function, the program jumps to the definition for the function being called, executes the function's body, and then returns to the point in the program where the function was called and resumes executing the program.
As mentioned earlier, functions are an example of a control structure. Let's look at some examples.
Let's look at a Python example. In a previous lab, we wrote a program that took a temperature in Fahrenheit and converted it to Celsius.
What that program might have looked like:
# input temp
f = float(input("Enter a temperature in Fahrenheit: "))
# convert to celsius
c = (f -32) * 5/9
# show output
print(f"{f} degrees Fahrenheit is equal to {c} degrees celsius")
For more on f strings
in Python: https://realpython.com/python-f-strings/
This isn't a terribly long program to write out, but if we need to perform this conversion regularly, we might want to just write it out once and be able use that working code elsewhere in our program.
We can rewrite this program as a function that we can access elsewhere in our program.
# define function
def tempConvert():
fahrenheit = float(input("Enter a temperature in Fahrenheit: ")) # get temperature
celsius = (fahrenheit -32) * 5/9 # convert to celsius
print(f"{fahrenheit} degrees Fahrenheit is equal to {celsius} degrees celsius") # show output
Then, elsewhere in our program, we could call that function using its name.
# sample function call
tempConvert()
But we could break down this program further, thinking about the underlying steps:
- Get user input for Fahrenheit temperature
- Convert to celsius
- Show output
We could create modular pieces for each of these tasks.
# function for getting input
def getFahrenheit():
fahrenheit = float(input("Enter a temperature in Fahrenheit: "))
return fahrenheit
# function for converting to Celsius
def convertTemp(fahrenheit):
celsius = (fahrenheit -32) * 5/9
return celsius
# function for returning output
def result(fahrenheit, celsius):
print(f"{fahrenheit} degrees Fahrenheit is equal to {celsius} degrees celsius")
And we could create a combined function from each of those three individual functions.
# combined function
def combined():
fahrenheit = getFahrenheit()
celsius = convertTemp(fahrenheit)
result(fahrenheit, celsius)
To run our entire temperature conversion program, we would just need to call the combined()
function using its name.
# combined temperature conversion program function call
combined()
We'll dig into what's happening here in more detail later in this lab. To summarize, we created a function for each piece of our conversion program (getFahrenheit
, convertTemp
, result
), and then created a main
function that combined those three steps.
Putting that all together:
# function for getting input
def getFahrenheit():
fahrenheit = float(input("Enter a temperature in Fahrenheit: "))
return fahrenheit
# function for converting to Celsius
def convertTemp(fahrenheit):
celsius = (fahrenheit -32) * 5/9
return celsius
# function for returning output
def result(fahrenheit, celsius):
print(f"{fahrenheit} degrees Fahrenheit is equal to {celsius} degrees celsius")
# combined function
def combined():
fahrenheit = getFahrenheit()
celsius = convertTemp(fahrenheit)
result(fahrenheit, celsius)
# combined temperature conversion program function call
combined()
Let's say we want to create a function that prints an input string three times. Breaking down the steps of that program:
- Get input string
- Print the string (3x)
We might also need some way of tracking how many times we've printed the string so it stops at three.
One way we could approach this would be using a count
variable and a while
statement.
# assign count to 0
count = 0
# get input string
message = input("Type your message here: ")
# while statement
while count < 3:
print(message) # print message
count += 1 # reassign count
Thinking through how this program runs:
count
starts at0
and increases by an increment of1
each time the code nested underwhile
runs- The code nested under
while
will keep running until the initial condition (count < 3
) is no longer true
We can test this program to make sure the output is what we expect. How that we have a program that prints an input string three times, we can create the named function.
# function definition
def printThreeTimes(string):
Then under the def
keyword will go the lines of code that execute our program.
# function definition
def printThreeTimes():
count = 0 # assign count
message = input("Type your message here: ") # get input message
while count < 3: # while statement
print(message) # print message
count += 1 # reassign count
Now when we run this block of code, there won't be any output because we are just creating or defining the printThreeTimes
function. When we need to use the function, we can call it using its name.
# sample function call
printThreeTimes()
Putting that all together:
# function definition
def printThreeTimes():
count = 0 # assign count
message = input("Type your message here: ") # get input message
while count < 3: # while statement
print(message) # print message
count += 1 # reassign count
# function call
printThreeTimes()
But let's say we don't want to use an input()
statement as part of the function- what if we wanted to pass a specific value to the function?
First, let's build a program that accomplishes this task.
# assign string
message = "There's no place like home"
# assign count
count = 0
# while statement
while count < 3:
print(message) # print message
count += 1 # reassign count
To create the function:
def printThreeTimes(message):
count = 0 # assign count
while count < 3: # while statement
print(message) # print message
count += 1 # reassign count
Remember in this scenario, we are going to pass a specific value to the function, rather than asking for an input as part of the function.
So how would we call our modified printThreeTimes
function? We would pass a string object to the function.
# assign string
message = "There's no place like home"
# function definition
def printThreeTimes(message):
count = 0 # assign count
while count < 3: # while statement
print(message) # print message
count += 1 # reassign count
# function call
printThreeTimes(message)
|
Additional Considerations |
This modified example introduces a couple of key concepts for working with functions:
- Inside a function, the arguments are assigned to local variables, or placeholder variables. These local variables are called parameters.
- Key term: parameter
- The name of the parameter inside the function is separated or isolated from the name outside the function. This separation of namespaces is called scoping.
- Key term: scoping
An example of scoping:
# assign x variable
x = 1
# function definition
def print_number(x):
print(x)
# print x variable
print(x)
# call named function
print_number(2)
The value of x
in the first line of this program has nothing to do with the purpose x
is serving in the function definition.
In short, the placeholder variables (or parameters) we use inside the function definition are separated or isolated from any instance where a variable or parameter with the same name is used outside the function definition.
Click here to learn more about scope in Python, via W3Schools.
![]() |
Named Functions in Python Comprehension Check |
|
Lab Notebook Question 1 |
Let's say we want to create a function that prints an input string a specific number of times.
Breaking down the steps of that program:
- Get the input string (
message
) - Get the number of times (
x
) - Print the string
x
number of times
We might also need some way of tracking how many times we've printed the string so it stops at the specified number.
Q1A: Describe how you would start building out a program to accomplish this task? What functions, statements, or keywords would you need to use? How would you start to organize this program?
Q1B: See where you can get with writing this program. What parts of the program were you able to get working? Where did you run into challenges? Answer to this question includes program + comments that document process and explain your code.
Here is one approach to this task:
We can use two input statements to get message
and x
. And one way we could approach printing the string x
number of times would be to use a count
variable and a while
statement.
# input statement for string
message = input("Enter your message here: ")
# input statement for number of times
x = int(input("How many times do you want this statement to print? Enter a number value."))
# assign count
count = 0
# while statement
while count < x:
print(message) # print message
count += 1 # reassign count
Now to create a function using this program.
# function definition
def printNTimes():
message = input("Enter your message here: ") # input statement for string
x = int(input("How many times do you want this statement to print? Enter a number value.")) # input statement for number of times
count = 0 # assign count
while count < x: # while statement
print(message) # print message
count += 1 # reassign count
# function call
printNTimes()
Q1C: How does the sample program compare to your approach? What was similar? What was different? How are you thinking differently (if at all) about how to approach this type of program?
But let's say we don't want to use an input()
statement as part of the function- what if we wanted to pass specific values to the function?
Q2A: Modify the program you built for the previous section of the lab to take specific values as inputs (rather than get inputs as part of the function). Answer to this question includes program + comments that document process and explain your code.
Q2B: Then, create a named function and function call for this program. Answer to this question includes program + comments that document process and explain your code.
Q2C: What parts of the program were you able to get working? Where did you run into challenges?
|
Additional Considerations |
We can add comments to a function definition by including a docstring under the function header.
- Key term: docstring
As we've learned previously, single-line comments in Python are declared using the #
symbol, and multi-line comments in Python are declared using the '''
symbol.
Docstrings are declared using triple single quotes ('''
) or triple double quotes ("""
).
- Best practice is to start the docstring just below the function header.
- Another best practice for docstrings is to begin with a capital letter and end with a period.
- The docstring should briefly describe what the function does.
Let's see this in action with an example from earlier in the lab.
# function definition
def printThreeTimes():
'''Prints an input string three times'''
count = 0 # assign count
message = input("Type your message here: ") # get input message
while count < 3: # while statement
print(message) # print message
count += 1 # reassign count
We have a couple options for accessing the contents of the docstring elesewhere in the program. We can use the __doc__
method (underscore, underscore, doc, underscore, underscore).
print("Using __doc__:")
print(printThreeTimes.__doc__)
Or we can use the help()
function.
print("Using help:")
help(printThreeTimes)
Multi-line docstrings can be used to provide additional description about the named function, including information about parameters, arguments, and returns.
Click here to learn more about docstrings in Python, via Python.org documentation.
Functions that yield a result are considered fruitful. To output a result, a function uses the return
statement to pass results back to the function call.
- Key term: fruitful function(s)
Functions that perform a computation but do not yield a result are considered void. By default, the return value for void functions is None
.
- Key term: void function(s)
![]() |
Python Function Considerations Comprehension Check |
|
Lab Notebook Questions 3-5 |
Q3: Write a function is_even that determines whether or not a number n is even. Include the function definition as well as a sample function call. Answer to this question includes program + comments that document process and explain your code.
Q4: Write a function average that determines the average value of a list. Include the function definition as well as a sample function call. Answer to this question includes program + comments that document process and explain your code.
Q5: Write a function uniq that takes a list and returns a new list containing only unique values. Include the function definition as well as a sample function call. Answer to this question includes program + comments that document process and explain your code.
|
Putting It All Together |
Using functions to promote modular programming serves a few key purposes:
- Yields more concise code* by eliminating the need to write out code for the same task multiple times
- Improves improve code readability
- Helps us more effectively test and debug code
- Because we are creating reusable pieces or building blocks of code, we can more readily pinpoint where things are going wrong or not working in our code.
- Promotes code reuse and modularity by allowing us to define and call functions for common tasks
This may seem overly-complicated for a relatively simple program.
But imagine all kinds of more complex tasks we might want to accomplish in a programming environment- analyzing data, generating visualizations, creating textures, building interaction objects, etc. All of that becomes possible through functions- modular building blocks that can be combined to accomplish more complex tasks.
|
Modules, Packages & Libraries |
As we move forward in Python, we're going to be encountering the terms package
, module
, and library.
All of these terms refer to external Python programs that we can use in our program without having to recreate the entire original code. We can think of these resources as "expansion packs" for Python that expand or extend the programming language's built-in functionality.
A few preliminary definitions...
- A module is a Python file that typically includes specialized functions and variables. Modules typically have
.py
file extensions. - A single or simple directory of modules is called a package. Packages are typically a simple directory with multiple modules.
- A library includes blocks of code that can be reused within a program. Libraries are a collection of modules that have a much more complex directory/sub-directory/etc structure than packages
Some modules, packages, and libraries are built-in to Python and require no additional installation. Others have to be installed (typically at the command line, or in the terminal) before you can import and use them in a program.
Built-in functions don't require any extra steps to be able to access them in the programming environment. For example, you can see the source code for the print()
function, contained in Python's bltinmodule.c file in the source code. But all we have to do is use the function name in our program.
In this example, we have a game
package that includes sound
, image
, and level
sub-packages. Each of those sub-packages includes specific modules. For example, the sound
sub-package includes the load.py
, play.py
, and pause.py
modules.
We can bring these modules into our program using an import
statement.
For example, let's say we wanted to bring the start.py
module from the level
sub-package into our program.
We could do this using the following import
statement at the start of our program.
from game.level import start
Now, we would be able to access any of the functions (or other code) contained in the start.py
module, because we have imported them into our program.
For more on modules, packages, and libraries in Python:
- Programmiz, "Python Package
- GeeksForGeeks, "What is the difference between Python's Module, Package and Library?" (30 September 2022)
- John Sturtz, "Python Modules and Packages - An Introduction" Real Python
![]() |
Code Reuse & Modularity in Python Comprehension Check |
Q6A: Select one of the following Python modules to explore:
- numbers (numeric abstract base classes)
- math (mathematical functions)
- cmath (mathematical functions for complex numbers)
- decimal (decimal fixed point and floating arithmetic)
- fractions (rational numbers)
- random (generate pseudo-random numbers)
- statistics (mathematical statistics functions)
Or one of the other modules (starting with "Numeric and Mathematical Modules") on the Python Standard Library page.
Q6B: Explore the Python documentation (and other materials as needed) to address the following questions:
- What is this module designed to do, or what kinds of tasks does it support?
- What are some of the specific functions contained in this module?
- How would we import this module into a Python program?
- How would we import specific functions from this module into a Python program?
NOTE: The last two items (importing the module, importing functions from the module) involve a code component. Your answer for these items should include a Python program + comments that document process and explain your code.
Q7: Describe in your own words the value or utility of functions, particularly in relation to the concepts of code reuse and modularity.
- NOTE: You are welcome to include code as part of this answer, but a code component is not required.
Moving forward, we'll submit lab notebooks as .py
files.
One option is to have a .py
file that you use to run code and test programs while working through the lab. When ready to submit the lab notebook, you add comments and remove extraneous materials.
Another option is to have an "official" .py
file that you are using as a lab notebook (separate from your working/testing file). Use comments in Python to note when you are starting a new question (as well as answering a question).
- Example:
Lab_Notebook_Walden.py
What gets submitted as the lab notebook is the Lab_Notebook_Walden.py
file.
- When in doubt, use comments
- Be sure you are using comments to note what question you're responding to
Click here to make a copy of the Replit template for this lab.
Alternatives:
.py
template (Google Drive, ND users)- Jupyter Notebook,
.ipynb
(Google Colab, ND users)
Q1A: Describe how you would start building out a program to accomplish this task (print a string a specific number of times)? What functions, statements, or keywords would you need to use? How would you start to organize this program?
Q1B: See where you can get with writing this program. What parts of the program were you able to get working? Where did you run into challenges? Answer to this question includes program + comments that document process and explain your code.
Q1C: How does the sample program compare to your approach? What was similar? What was different? How are you thinking differently (if at all) about how to approach this type of program?
Q2A: Modify the program you built for the previous section of the lab to take specific values as inputs (rather than get inputs as part of the function). Answer to this question includes program + comments that document process and explain your code.
Q2B: Then, create a named function and function call for this program. Answer to this question includes program + comments that document process and explain your code.
Q2C: What parts of the program were you able to get working? Where did you run into challenges?
Q3: Write a function is_even that determines whether or not a number n is even. Include the function definition as well as a sample function call. Answer to this question includes program + comments that document process and explain your code.
Q4: Write a function average that determines the average value of a list. Include the function definition as well as a sample function call. Answer to this question includes program + comments that document process and explain your code.
Q5: Write a function uniq that takes a list and returns a new list containing only unique values. Include the function definition as well as a sample function call. Answer to this question includes program + comments that document process and explain your code.
Q6A: Select one of the following Python modules to explore:
- numbers (numeric abstract base classes)
- math (mathematical functions)
- cmath (mathematical functions for complex numbers)
- decimal (decimal fixed point and floating arithmetic)
- fractions (rational numbers)
- random (generate pseudo-random numbers)
- statistics (mathematical statistics functions)
Or one of the other modules (starting with "Numeric and Mathematical Modules") on the Python Standard Library page.
Q6B: Explore the Python documentation (and other materials as needed) to address the following questions:
- What is this module designed to do, or what kinds of tasks does it support?
- What are some of the specific functions contained in this module?
- How would we import this module into a Python program?
- How would we import specific functions from this module into a Python program?
NOTE: The last two items (importing the module, importing functions from the module) involve a code component. Your answer for these items should include a Python program + comments that document process and explain your code.
Q7: Describe in your own words the value or utility of functions, particularly in relation to the concepts of code reuse and modularity.
- NOTE: You are welcome to include code as part of this answer, but a code component is not required.