Question 1

Implement a class LoopList that has a method at_index. If at_index is called with an index that is too large, the LoopList will loop around back to the beginning.

class LoopList(object):
    """
    >>> x = LoopList([3, 1, 4])
    >>> [x.at_index(i) for i in range(10)]  # loops around!
    [3, 1, 4, 3, 1, 4, 3, 1, 4, 3]
    """
    pass

Toggle Solution

class LoopList(object):
    """
    >>> x = LoopList([3, 1, 4])
    >>> [x.at_index(i) for i in range(10)]  # loops around!
    [3, 1, 4, 3, 1, 4, 3, 1, 4, 3]
    """
    def __init__(self, lst):
        self.lst = lst

    def at_index(self, idx):
        return self.lst[idx % len(self.lst)]

Question 2

Draw the environment diagram (this one’s hard!).

def campa(nile):
    def ding(ding):
        nonlocal nile
        def nile(ring):
            return ding
    return nile(ding(1914)) + nile(1917)

ring = campa(lambda nile: 100)

Toggle Solution

When looking through the environment diagram, be very very careful about the order of operations! Remember that for every function call, we do:

  1. Evaluate the operator (this means resolving the name of the function to the function itself!)
  2. Evaluate the operands, from left to right.
  3. Apply the operator on the operands.