Nonlocal Practice Problems

Basic Concepts

  1. Summarize in your own words what the nonlocal keyword does, and what problem nonlocal tries to solve. Modify this definition accordingly as you get more practice down in the next few sections.
  2. How does nonlocal relate to the general discussion of object mutation? Compare and contrast what a programmer tries to do in nonlocal versus in object mutation
  3. Does nonlocal work on names in the global frame? Why/why not?
  4. Give the simplest example you can that uses nonlocal correctly.
  5. Does nonlocal treat parameter names differently from regular names?
  6. Describe explicitly the lookup procedure nonlocal does when the keyword is encountered.

Experimentation

Now that you have a good understanding of nonlocal, it's time to understand misconceptions about nonlocal. Try simple examples with nonlocal where the code fails. (If you really can't think of examples, revisit Discussion 7.)

  1. What does the error message say?
  2. Given what you know about the motivation, why do you think Python does not allow what you just did?

Environment Diagrams

Once you are familiar with the motivation behind nonlocal, you can generate your own environment diagram questions! As always, you can check your answers on PythonTutor, but make sure that you have it on Python 3.

For each problem, you should write down what we are trying to keep track with the nonlocal name.

In []:
def make_draw(tickets):
    quantity = tickets
    def draw():
        nonlocal quantity
        quantity -= 1
        return quantity
    return draw
drawing = make_draw(100)
drawing()
drawing()
draw()
In []:
def mutate_two(lst1, lst2):
    curr_lst = lst1
    def mutate(x):
        nonlocal curr_lst
        curr_lst.append(x)
        curr_lst = lst2 if curr_lst is lst1 else lst1
    return mutate
lst1, lst2 = [1], [100]
mutator = mutate_two(lst1, lst2)
mutator(10)
mutator([3])
mutator('hello')
In []:
def fn(a, b, c):
    start_letter = 0
    remote = True
    def randomize():
        nonlocal a, b, c, start_letter
        a, b, c = b, c, a
        start_letter += start_letter % 3
        if remote:
            print(a)
    return randomize
strings = fn("i", "am", "Python")
strings()
strings()

For the following, you will not see anything as elaborate on the exam, but solving this diagram systematically (i.e. by following all the rules) will be great practice. It also introduces you to visualizing dictionaries in environment diagrams.

In []:
def bart_operator():
    location = "Berkeley"
    def change_loc(loc):
        nonlocal location
        location = loc
        print(loc)
    tasks = {'maintain': lambda car: 'Fixed car!', 'move': change_loc, \
             'call': lambda msg: print(msg + '? You got it.')}
    task = tasks['call']
    def work(status, arg):
        nonlocal task
        if status == "do":
            return task(arg)
        elif status == "change":
            if arg in tasks:
                task = tasks[arg]
            else:
                return "idk how to do that"
    return work
dickson = bart_operator()
dickson("do", "Fix wires")
dickson("change", "move")
dickson("do", "Union City")

Afterword

For those of you who like to read about how nonlocal came to be, PEP 3014 describes completely the discussion Python developers have had over nonlocal and the rationale behind this new construct.