Homework 10 Solutions

Solution Files

You can find the solutions in hw10.py.

Required Questions

Iterators and Generators

Q1: Scale

Implement an iterator class called ScaleIterator that scales(multiplies) elements in an iterable s by a number k.

Be careful! If your __next__ method never raises StopIteration, you might loop forever.

class ScaleIterator:
    """An iterator the scales elements of the iterable s by a number k.

    >>> s = ScaleIterator([1, 5, 2], 5)
    >>> for elem in s:
    ...     print(elem)
    5
    25
    10
    >>> m = ScaleIterator([1, 2, 3, 4, 5, 6], 2)
    >>> [next(m) for _ in range(5)]
    [2, 4, 6, 8, 10]
    """
    def __init__(self, s, k):
self.s = iter(s) self.k = k
def __iter__(self): return self def __next__(self):
return next(self.s) * self.k

Use Ok to test your code:

python3 ok -q ScaleIterator

Q2: Amplify

Implement amplify, a generator function that takes a one-argument function f and a starting value x. The element at index k that it yields (starting at 0) is the result of applying f k times to x. It terminates whenever the next value it would yield is a falsy value, such as 0, "", [], False, etc.

def amplify(f, x):
    """Yield the values x, f(x), f(f(x)), ... that are all truthy values
    and stop yielding once the sequence reaches the first falsy value.

    >>> gen1 = amplify(lambda s: s[1:], 'boxes')
    >>> [next(gen1) for _ in range(5)]
    ['boxes', 'oxes', 'xes', 'es', 's']
    >>> try:
    ...     next(gen1)
    ... except StopIteration:
    ...     print('Correctly raised StopIteration')
    ... else:
    ...     print('Expected StopIteration error but was not raised')
    Correctly raised StopIteration
    >>> gen2 = amplify(lambda x: x // 2 - 1, 14)
    >>> [next(gen2) for _ in range(3)]
    [14, 6, 2]
    >>> try:
    ...     next(gen2)
    ... except StopIteration:
    ...     print('Correctly raised StopIteration')
    ... else:
    ...     print('Expected StopIteration error but was not raised')
    Correctly raised StopIteration
    """
while x: yield x x = f(x)

Use Ok to test your code:

python3 ok -q amplify

Q3: Countdown

Write both a generator function and an iterator (that is not a generator) that count down to 0.

def countdown(n):
    """
    A generator that counts down from N to 0.
    >>> for number in countdown(5):
    ...     print(number)
    ...
    5
    4
    3
    2
    1
    0
    >>> for number in countdown(2):
    ...     print(number)
    ...
    2
    1
    0
    """
while n >= 0: yield n n = n - 1
class Countdown:
    """
    An iterator that counts down from N to 0.
    >>> for number in Countdown(5):
    ...     print(number)
    ...
    5
    4
    3
    2
    1
    0
    >>> for number in Countdown(2):
    ...     print(number)
    ...
    2
    1
    0
    """
    def __init__(self, cur):
        self.cur = cur

    def __next__(self):
if self.cur < 0: raise StopIteration self.cur -= 1 return self.cur + 1
def __iter__(self): """So that we can use this iterator as an iterable.""" return self

Use Ok to test your code:

python3 ok -q countdown
python3 ok -q Countdown

Walkthrough:

YouTube link

Submit Assignment

Submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. Lab 00 has detailed instructions.