Study Guide: Environments and HOF
Instructions
This is a study guide with links to past lectures, assignments, and handouts, as well as additional practice problems to assist you in learning the concepts.
Draw environment diagrams automatically with Python Tutor.
Assignments
Important: For solutions to these assignments once they have been released, see the main website
Handouts
Lectures
Readings
Environment Diagrams
Albert Wu's Environment Diagrams Guide provides an alternative view of the rules and additional practice.
Environment diagrams help us visualize Python's process. For each line of code we should first identify what kind of statement or expression it is and then execute the line according to the rules.
A couple tips:
- You can only bind names to values. No expressions (like
3 + 4
) allowed on environment diagrams! - Frames and functions both have parents.
- Primitive values which include booleans (
True
,False
), numbers (42
), and strings ('cs 61a'
) go directly in the box for the value of a binding. - Composite values and function values are drawn off to the side and require a pointer from the value box to the object.
Expressions
Primitive Expressions
- In the current environment return the value of the primitive expression. If the expression is just a number or a string, it evaluates to the Python representation of that number or string. If the expression is a name, look for the name in the current environment by following the lookup procedure by starting in the current frame and looking up each parent frame until the global frame.
Call Expressions
- Evaluate the operator, which could itself be another call expression.
- Evaluate the operands from left to right, each of which could be call expressions.
- Apply the operator (evaluated as a function) to the operands (evaluated as arguments). If this is a built-in function, we skip directly to the final result because we don't know how built-in functions are implemented. But if the function is user-defined, create a new frame in the environment diagram.
- Bind the formal parameters to the argument values (the evaluated operands).
- Evaluate the body of the function in the new frame.
- After evaluating the body of the function, return to the frame that called the function.
Statements
Assignment Statements
Note that assignment rules become more complicated with
nonlocal
.
- Evaluate the expression to the right of the assignment operator
=
. - Bind the variable name to the value of the expression in the current frame. Be sure you override the variable name if it had a previous binding.
def
Statements
- Draw the
func name(arg1, arg2, ...)
. - The parent of the function is wherever the function was defined (the frame we're currently in, since we're creating the function).
- Bind the name of the function to the function value in the current frame.
return
Statements
- Evaluate the expression to the right of
return
. - In the current frame, create a space for the return value which contains the
value of the
return
expression.
Interactive Environment Diagram Questions
Important: You may have to log in to your okpy account to be able to modify the interactive diagrams below.
Basic
Q1: Environment Diagrams - Basic
These questions were originally developed by Albert Wu and are included here for extra practice. We recommend checking your work in PythonTutor after filling in the diagrams for the code below.
Q1a
Draw the environment diagram that results from executing the code below.
Guiding Question:
- How does return behave differently than print?
def square1(x):
return x * x
def square2(x):
print(x * x)
a = square1(3)
b = square2(3)
Return value |
Return value |
Return value |
Q1b
Draw the environment diagram that results from executing the code below.
Guiding Questions:
- How many times do we call mul?
- How many frames do we draw for mul?
def square(x):
return x * x
def sum_of_squares(x, y):
return square(x) + square(y)
result = sum_of_squares(3, 4)
Return value |
Return value |
Return value |
Q1c
Draw the environment diagram that results from executing the code below.
Guiding Questions:
- What changes between the first time we call add and the second time?
- How does this affect our diagram?
from operator import add
first = add(3, 4)
def add(a, b):
return a + b
second = add(3, 4)
Return value |
Return value |
Return value |
Q1d
Draw the environment diagram that results from executing the code below.
Guiding Questions:
- Did the global values of score and opp_score change?
score, opp_score = 0, 0
def assign(arg0, arg1):
score = arg0
opp_score = arg1
return True
success = assign(3, 9001)
Return value |
Return value |
Return value |
Q1e
Draw the environment diagram that results from executing the code below.
Guiding Questions:
- What's the lookup procedure for goal?
- Does result ever show up in the diagram?
goal = 100
def foo(x):
y = x + goal
return b
result = foo(4)
Return value |
Return value |
Return value |
Q1f
Draw the environment diagram that results from executing the code below.
from operator import add, sub
def a_plus_abs_b(a, b):
if b < 0:
op = sub
else:
op = add
return op(a, b)
result = a_plus_abs_b(4, -4)
Return value |
Return value |
Return value |
Challenge
Q2: Environment Diagrams - Basic
These questions were originally developed by Albert Wu and are included here for extra practice. We recommend checking your work in PythonTutor after filling in the diagrams for the code below.
Q2c
Draw the environment diagram that results from executing the code below.
def fun(fun):
def time(time):
return fun(x)
x = 4
return time
def boo(x):
return x**2
x = 5
result = fun(boo)(10)
Return value |
Return value |
Return value |
Q2d
Draw the environment diagram that results from executing the code below.
from operator import sub
def trick(me, you):
sub = treat
return sub
def treat(me, you):
return sub(me, 1)
treat = trick
trick(3, 4)
Return value |
Return value |
Return value |
Q2e
Draw the environment diagram that results from executing the code below.
def easy(x):
def peasy(y):
def ironic(name):
return name(x, y)
return y
return peasy
result = easy(4)(easy)(2)
Return value |
Return value |
Return value |
Additional Practice Problems
These questions provide practice with drawing environment diagrams from scratch. We recommend solving these on paper and checking your work in PythonTutor.
Easy
Q3: Make Adder
Draw the environment diagram for the following code.
>>> def adder_maker(x):
... def adder(y):
... return x + y
... return adder
>>> add3 = adder_maker(3)
>>> add3(4)
______7
>>> sub5 = adder_maker(-5)
>>> sub5(6)
______1
>>> sub5(10) == add3(2)
______True
Q4: Alpaca Zebra
Draw the environment diagram for the following code.
def yak(zebra):
return 20 // zebra
def llama(alpaca):
zebra = 0
def yak(zebra):
return alpaca(zebra)
return yak
llama(yak)(4)
Verify your solution with Python Tutor.
Q5: Multiplication
Using a lambda
expression, complete the mul_by_num
function. This function
should take an argument and return a one argument function that multiplies any
value passed to it by the original number.
def mul_by_num(num):
"""
Returns a function that takes one argument and returns num
times that argument.
>>> x = mul_by_num(5)
>>> y = mul_by_num(2)
>>> x(3)
15
>>> y(-4)
-8
"""
"*** YOUR CODE HERE ***"
return ______
return lambda num2: num * num2
Medium
Q6: Community
>>> def troy():
... abed = 0
... while abed < 3:
... britta = lambda: abed
... print(abed)
... abed += 2
... annie = abed
... annie += 1
... abed = 6 # seasons and a movie
... return britta
>>> jeff = troy()
______0
2
>>> shirley = lambda: jeff
>>> pierce = shirley()
>>> pierce()
______6
Q7: Doge
Draw the environment diagram for the following code.
wow = 6
def much(wow):
if much == wow:
such = lambda wow: 5
def wow():
return such
return wow
such = lambda wow: 4
return wow()
wow = much(much(much))(wow)
You can check out what happens when you run the code block using Python Tutor.
Q8: Two Kinds of People
Draw the environment diagram for the following code.
def blondie(f):
return lambda x: f(x + 1)
tuco = blondie(lambda x: x * x)
angel_eyes = tuco(2)
Verify your solution with Python Tutor.
Q9: Reruns
>>> def troy():
... abed = 0
... while abed < 10:
... britta = lambda: abed
... abed += 1
... abed = 20
... return britta
...
>>> jeff = troy()
>>> shirley = lambda : jeff
>>> pierce = shirley()
>>> pierce()
______20