Lab 03 - For loops, Strings, & Comprehensions
Due by 11:59pm on January 23, 2025
In this lab you'll continue to practice your skills with fundamental Python concepts. Specifically, you'll be looking at
- for loops
- ranges
- strings
- lists
As always, you should read the entire assignment before starting on any part of it.
A note on testing: Throughout the lab questions you'll be prompted to run the tests on your code. This is a habit you should get into on all of your assignments and we'll prompt you to do it in the early ones. If you are testing as you go (as you should be), there will be many errors reported for the parts of the assignments that you haven't implemented yet. This is okay, you should just be looking for errors on the parts you have done and eliminate them before moving on.
Starter Files
Once you've read through the entire assignment, come back here and download lab03.zip. Inside the archive, you will find starter files for the questions in this lab.
Topics
For loops
For loops in Python provide a clean and efficient way to iterate over sequences such as lists, tuples, strings, or other iterable objects. They are particularly useful when you need to perform an operation on each item in a sequence or when you want to execute a block of code a specific number of times.
Basic Syntax
The basic syntax of a for loop in Python is:
for value in sequence:
# statement(s) to be executed
Here's how it works:
- The loop variable value takes on each element in the sequence one at a time.
- For each iteration, the code block inside the loop is executed.
- The loop continues until all elements in the sequence have been processed.
Example: Iterating Over a List
gymnasts = ["Brittany", "Lea", "Maya"]
for gymnast in gymnasts:
print(gymnast)
This will output:
Brittany
Lea
Maya
Nested For Loops
You can nest for loops within each other to iterate over multi-dimensional data structures:
gymnasts = [
["Brittany", 9.15, 9.4, 9.3, 9.2],
["Lea", 9, 8.8, 9.1, 9.5],
["Maya", 9.2, 8.7, 9.2, 8.8]
]
for gymnast in gymnasts:
for data in gymnast:
print(data, end=" ")
print() # New line after each gymnast
This will output each gymnast's name followed by their scores on the same line.
Ranges
The range()
function in Python generates a sequence of numbers, which is commonly used in for loops and list comprehensions (below).
Basic Range
The simplest form of range()
takes one argument, which is the end value (exclusive):
for num in range(6):
print(num) # Outputs: 0, 1, 2, 3, 4, 5
Specifying Start and End
You can specify both start and end values:
for num in range(1, 6):
print(num) # Outputs: 1, 2, 3, 4, 5
Using Step Size
The range()
function can also take a step size:
for num in range(0, 30, 3):
print(num) # Outputs: 0, 3, 6, 9, 12, 15, 18, 21, 24, 27
Counting Down
If you want your range to go backwards (from a large number to a smaller one), you need to use the step form of the function with a negative step size:
for num in range(10, 0, -1):
print(num) # Outputs: 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
Strings
In Python, strings are sequences of characters enclosed in quotation marks. There are three main ways to create strings, each with its own use cases and advantages.
String Creation
Single Quotes
The simplest way to create a string is by enclosing characters in single quotes:
greeting = 'Hello, World!'
Single quotes are often preferred for short strings and are especially useful when the string itself contains double quotes.
Double Quotes
Strings can also be created using double quotes:
message = "Python is awesome!"
Double quotes function identically to single quotes but are particularly useful when the string contains apostrophes or single quotes.
Triple Quotes
For multi-line strings, Python provides triple quotes using quotation marks:
long_text = """This is a multi-line string.
It can span across several lines
without needing explicit line breaks."""
Triple quotes are particularly useful for docstrings, long text passages, or when you need to preserve the formatting of the text.
Escape Sequences
Within strings, you can use escape sequences to represent special characters:
print("The Zen of Python claims, \"Readability counts.\"")
print('I\'ve got an apostrophe')
The backslash () is used to escape special characters, allowing you to include quotes within strings or represent newlines (\n), tabs (\t), and other special characters.
Splitting Strings
The split()
method divides a string into a list of substrings:
sentence = "This is a short sentence."
words = sentence.split()
print(words) # Output: ['This', 'is', 'a', 'short', 'sentence.']
By default, split()
uses whitespace as the delimiter, but you can specify a different delimiter as an argument.
.
F-Strings
To create an f-string, prefix the string with 'f' and include expressions in curly braces:
artist = "Bette Midler"
song = "The Rose"
place = 10
print(f"Landing at {place}: {song} by {artist}")
F-strings are more readable and efficient than older string formatting methods.
Lists
List Slicing
To create a copy of part of or all of a list, we can use list slicing. The
syntax to slice a list lst
is:
lst[<start index>:<end index>:<step size>]
This expression evaluates to a new list containing the elements of
lst
:
- Starting at and including the element at
<start index>
. - Up to but not including the element at
<end index>
. - With
<step size>
as the difference between indices of elements to include.
If the start, end, or step size are not explicitly specified, Python has default values for them. A negative step size indicates that we are stepping backwards through a list when including elements.
>>> lst = [6, 5, 4, 3, 2, 1, 0]
>>> lst[0:3]
[6, 5, 4]
>>> lst[:3] # Start index defaults to 0
[6, 5, 4]
>>> lst[3:7]
[3, 2, 1, 0]
>>> lst[3:] # End index defaults to len(lst)
[3, 2, 1, 0]
>>> lst[::2] # Skip every other; step size defaults to 1 otherwise
[6, 4, 2, 0]
>>> lst[::-1] # Make a reversed copy of the entire list
[0, 1, 2, 3, 4, 5, 6]
You can also index, use in
, use len()
, and slice with strings.
>>> s = "abcde"
>>> s[0] # retrieves the character at index 0
'a'
>>> 'b' in s
True
>>> len(s)
5
>>> s[2:]
'cde'
List Comprehensions
List comprehensions are a compact and powerful way of creating new lists out of sequences.
Let's say we wanted to create a list containing the numbers between 0 and 4, this is one way to do it:
>>> numbers = []
>>> for i in range(5):
... numbers += [i] # or `numbers.append(i)`
>>> numbers
[0, 1, 2, 3, 4]
Using list comprehensions, we can create the same list but in more compact way.
The simplest syntax for a list comprehension is the following:
[<expression_to_add> for <element> in <sequence>]
The syntax is designed to read like English: “Add and compute the expression for each element in the sequence."
Trying to create the same numbers
list above, we can do it using a list comprehension as so:
>>> numbers = [i for i in range(5)]
>>> numbers
[0, 1, 2, 3, 4]
Compare the similarities and difference of creating the
numbers
list. What syntax is missing in the list comprehension version? What is the same?
In some cases, we might want to add a condition on to which elements we adding:
>>> lst = []
>>> for i in [1, 2, 3, 4]:
... if i % 2 == 0: # if `i` is an even number
... lst = lst + [i**2]
>>> lst
[4, 16]
You can add a condition to list comprehensions. The general syntax for a list comprehension is the following:
[<expression_to_add> for <element> in <sequence> if <conditional>]
where the if <conditional>
section is optional.
The syntax is designed to read like English: “Add and compute the expression for each element in the sequence (if the conditional is true for that element).” For example, using the same example above:
>>> [i**2 for i in [1, 2, 3, 4] if i % 2 == 0]
[4, 16]
This list comprehension will:
- Add and compute the expression
i**2
- For each element
i
in the sequence[1, 2, 3, 4]
- Where
i % 2 == 0
(i
is an even number),
and then put the resulting values of the expressions into a new list.
In other words, this list comprehension will create a new list that
contains the square of every even element of the original list
[1, 2, 3, 4]
.
Both are completely valid, but the list comprehension is more compact and the more "Pythonic" way to do that operation. List comprehensions often seem odd when you first see them, but as you use them more, they become easier to understand and create.
It will be very helpful look at Python's builtin list methods for adding and removing elements to a list if you are unfamiliar with Python lists. (It is described at the very bottom of this lab in the 'Additional List Methods' section.)
Required Questions
Q1: Average Temperature
You are given a list of daily temperatures. Write a function, average_temperature()
, that is passed that list as a parameter, computes the average temperature, and returns the average. For the lab, use a for
loop to iterate over the temperatures.
def average_temperature(temps):
""" Given a list of temperatures, TEMPS, compute the average
temperature and return it to the user
>>> temp_data = [72.2, 68.7, 67.4, 77.3, 81.6, 83.7]
>>> average_temperature(temp_data)
75.15
"""
### Your code here
Test your code
Start with the doctests:
python3 -m doctest lab03.py
You should see zero errors for average_temperature
. If there are errors for this function, fix them and keep testing until they are gone.
Next run the pytests:
pytest -vv
Again, you should see zero errors for tests that include average_temperature
in their name. If there are errors for this function, fix them and keep testing until they are gone.
Discuss the following with your group:
- How would you do this with a
while
loop? - Which form you do find easier to understand? Easier to implement?
- Can you think of any situations where the
for
loop wouldn't work?
Q2: High Temperatures
You are again given a list of daily temperatures. Now write a function, hot_days()
, that takes that list of temperatures and counts the number of days the temperature is at least five degrees above the average. The function should print out the number of days and the average temperature in the following format:
There were 2 day(s) more than 5 degrees above the average of 75.2.
You'll need to call your average_temperature()
function to get the average so make sure it is working first.
def hot_days(temps):
"""
Given a list of temperatures, TEMPS, count the number of days
more than five degrees above the average. Print the number of
days and the average and return the number of days.
>>> temp_data = [72.2, 68.7, 67.4, 77.3, 81.6, 83.7]
>>> hot_days(temp_data)
There were 2 day(s) more than 5 degrees above the average of 75.2.
2
"""
### Your code goes here
Test your code
Start with the doctests:
python3 -m doctest lab03.py
You should see zero errors for hot_days
. If there are errors for this function, fix them and keep testing until they are gone.
Next run the pytests:
pytest -vv
Again, you should see zero errors for tests that include hot_days
in their name. If there are errors for this function, fix them and keep testing until they are gone.
Q3: Palindrome
A palindrome is a number, word, or phrase that looks the same written forward or backwards. For example, 'abba' and '13531' are both palindromes. So is the phrase "Madam, I'm Adam" (if you ignore the punctuation). For this lab, we're only going to work with single words.
Write a function is_palindrome()
that takes in a single word and determines if it is a palindrome or not. The function should return True
if it is, and False
otherwise. Additionally, it should print a message indicating if it is a palindrome or not. The output should look like this:
apple is not a palindrome ## for a word that is not a palindrome
kayak is a palindrome ## for a word that is
For this lab, you don't have to worry about capitalization. All of the tests will be just use lowercase letters.
def is_palindrome(word):
"""
Given a single word, WORD, determine if it is a palindrome or not.
Print a message that includes the word stating it is or is not a
palindrome and return True if it is and False otherwise
>>> is_palindrome('rotator')
rotator is a palindrome.
True
>>> is_palindrome('apple')
apple is not a palindrome.
False
"""
### Your code goes here
Test your code
Start with the doctests:
python3 -m doctest lab03.py
You should see zero errors for is_palindrome
. If there are errors for this function, fix them and keep testing until they are gone.
Next run the pytests:
pytest -vv
Again, you should see zero errors for tests that include is_palindrome
in their name. If there are errors for this function, fix them and keep testing until they are gone.
Discuss with your group:
- How would you extend this function to handle capitalization?
- How would you extend this function to ignore spaces and punctuation so you can process phrases?
- How would you extend this function to handle numbers?
Q4: Even Weighted - Comprehension version
This is the same 'Even Weighted' problem from Lab 2, but this time, we want you to implement it using a list comprehension instead of a while loop. When you are done, the function should be a single line long
Feel free to look at the code you submitted in Lab 2. By working with already working code, this will help you understand how the two different forms are related to one another.
Implement the function even_weighted
that takes a list s
and returns a new list that keeps only the even-indexed elements of s
and multiplies those elements by their index in the original list.
def even_weighted(s):
"""
>>> x = [1, 2, 3, 4, 5, 6]
>>> even_weighted(x)
[0, 6, 20]
"""
return # Your code goes here
Hint: Recall that a even number is a number that is evenly divisible by 2 and therefore has 0 remainder. We can use the modulo operator
%
to find the remainder and ensure it is 0:number % 2 == 0
Test your code
Start with the doctests:
python3 -m doctest lab03.py
You should see zero errors for even_weighted
. If there are errors for this function, fix them and keep testing until they are gone.
Next run the pytests:
pytest -vv
Again, you should see zero errors for tests that include even_weighted
in their name. If there are errors for this function, fix them and keep testing until they are gone.
Discuss with your group:
Compare the implementation you did here with the one from the previous Lab.
- Which is easier to understand?
- Which uses less code?
- Do you understand the mapping between the two implementations and how the various parts correspond?
Submit
Once the pytests are all passing, your assignment is complete and ready to submit. Submit your lab03.py
file to Gradescope to receive credit.
Submissions will be in Canvas.