Day 27 - Iteration in Python
Skills: 9
Pre-reading: 9.1.8 (skip 9.1.8.5, since we've already seen that on Day 15).
Supplementary Videos: For Loops in Python
Intro (10 mins)
- Today we focus on traversing and transforming lists in Python using for loops, and compare with Pyret's approaches.
- Lists in Python use the
listgeneric type, and like in Pyret, the type of the elements should be specified. The syntax in Pyret uses<>to specify a type for the elements, such asList<Number>. Python uses[]as inlist[float]orlist[str].
Example: Summing a List
-
Python:
day27.pydef sum_list(num_list: list[float]) -> float:
"""Returns the sum of all numbers in the list."""
run_total = 0
for num in num_list:
run_total = run_total + num
return run_totaltest_day27.pyimport pytest
from day27 import *
def test_sum_list_empty():
assert sum_list([]) == 0
def test_sum_list_nonempty():
assert sum_list([1, 2, 3]) == 6 -
Pyret (
for eachloop):day27.arrfun sum-list-for(numlist :: List<Number>) -> Number block:
doc: "Returns the sum of all numbers in the list using a for loop."
var sum = 0
for each(n from numlist):
sum := sum + n
end
sum
where:
sum-list-for([list: 1, 2, 3]) is 6
sum-list-for([list: ]) is 0
end -
Pyret (recursive):
day27.arrfun sum-list(numlist :: List<Number>) -> Number:
doc: "Returns the sum of all numbers in the list."
cases (List) numlist:
| empty => 0
| link(fst, rst) => fst + sum-list(rst)
end
where:
sum-list([list: 1, 2, 3]) is 6
sum-list([list: ]) is 0
end(While Python can process lists recursively, it's not typically done.)
Class Exercises (45 mins)
For each function, follow the full design recipe: type signature, docstring, tests, and code. Put the tests in test_day27.py, the rest in day27.py.
-
Design a Python function
product_list(nums: list[float]) -> floatthat returns the product of all numbers in the list (1 for empty list). -
Design a Python function
count_occurrences(items: list[str], target: str) -> intthat returns how many timestargetappears in the list. -
Design a Python function
filter_by_prefix(words: list[str], prefix: str) -> list[str]that returns a list of all words starting with the given prefix. In Python, if you have a strings, you can check if it starts with a prefix usings.startswith(prefix). -
Design a Python function
reverse_list(lst: list) -> listthat returns a new list with the elements in reverse order (do not usereversed()or[::-1]). In this problem, you can safely ignore the errors from Pylint about the type of elements in the list. The syntax to specify element types (such as inlist[str]) is only a hint for programs like Pylint to analyze the code for any type mismatches. The code will execute (but may lead to run-time errors) without such hints. Test this function on a list of numbers as well as a list of strings. The way in which the function works should be independent from the type of element in the list. -
Design a Python function
all_with_letter(words: list[str], letter: str) -> list[str]that returns all words containing the given letter. In Python, you can check if a string contains a letter usingletter in word. -
For one of the above problems, write the equivalent function in Pyret using both recursion and a
for eachloop.
Wrap-up (5 mins)
- Python for loops and mutable accumulators are a common way to process lists. While recursion can be done, it is less idiomatic in Python for lists (for trees,
forloops are much more difficult, and recursion is idiomatic). - Pyret supports both recursion and iteration; both approaches have strengths.