Diagnostic 1: Week 1 review
Functions and expressions
Question 1
Try running the following code in Python:
x, y = 42, 0
def swap(a, b):
"""Reassigns variables x and y to b and a, respectively."""
x, y = b, a
swap(x, y)
result = x / y
You should see an error occur on the last line:
ZeroDivisionError: division by zero
It seems like calling swap(x, y) didn't actually swap the variables! Why?
When swap is called, Python creates a new frame (let's call it f1). When
Python executes the line x, y = b, a, it sees that f1 doesn't contain
variables called x and y, so it creates local variables x and y in
f1. It does not reassign variables in the global frame.
What happens if we change the definition of swap to
def swap(a, b):
a, b = b, a
A ZeroDivisionError still occurs. Instead of creating two new local variables
x and y in f1, now Python just reassigns the local variables a and b.
The global variables x and y remain untouched.
print vs. return
Question 2
Suppose the following functions are entered into an interactive Python session:
def squirrel(facts):
if facts >= 60:
return facts
else:
print('Hungry')
def berkeley(facts, squirrel):
print('acorn')
status = squirrel(facts)
if status:
return 3
else:
print(4)
For each of the expressions in the table below, write all the lines that the interpreter would display.
- The output may have multiple lines.
- If it would display a function, write FUNCTION.
- If it would cause an error, write ERROR.
- You should include any lines displayed before an error.
The first row has been given to you as an example.
Remember from Lab 2 that
Noneis a false-y value, and a non-empty string is a truth-y value.
| Expression | Evaluates to | Displays in the interpreter: |
|---|---|---|
| print(42) | None | 42 |
| berkeley(squirrel, 100) | ||
| berkeley(70, squirrel) | ||
| berkeley(50, squirrel) |
Answers:
| Expression | Evaluates to | Displays in the interpreter: |
|---|---|---|
| print(42) | None | 42 |
| berkeley(squirrel, 100) | ERROR | acorn ERROR |
| berkeley(70, squirrel) | 3 | acorn 3 |
| berkeley(50, squirrel) | None | acorn Hungry 4 |
Control structures
Question 3
Implement the function ordered_two_digits(n), where n is a non-negative
integer (it can be 0). ordered_two_digits returns True if the tens digit of
nis larger than the ones digit of n. For example,
Calling
ordered_two_digitson these numbers will returnTrue:- 52
- 1342
Calling
ordered_two_digitson these numbers will returnFalse:- 25
- 55
- 1234
- 9 (interpreted as 09)
- 0 (interpreted as 00)
Hint: You can use the // and % operators to separate digits.
Note: Your solution should only fill in the blank — you do not need more than one line for this solution.
def ordered_two_digits(n):
"""Returns True if the tens digit of n is larger than the ones digit.
>>> ordered_two_digits(52)
True
>>> ordered_two_digits(1342)
True
>>> ordered_two_digits(25)
False
>>> ordered_two_digits(55)
False
>>> ordered_two_digits(1234)
False
>>> ordered_two_digits(9)
False
>>> ordered_two_digits(0)
False
"""
"*** YOUR CODE HERE ***"
return ______
return (n // 10) % 10 > n % 10
The ones digit of a number can be calculated with n % 10. The tens digit of a
number can be calculated with (n // 10) % 10 (remove the ones digit, then get
the last digit of the new number).
Question 4: Two equal
Implement a function two_equal that takes three integer arguments and returns
whether exactly two of the arguments are equal and the third is not.
def two_equal(a, b, c):
"""Return whether exactly two of the arguments are equal and the
third is not.
>>> two_equal(1, 2, 3)
False
>>> two_equal(1, 2, 1)
True
>>> two_equal(1, 1, 1)
False
>>> result = two_equal(5, -1, -1) # return, don't print
>>> result
True
>>> two_equal(0, 0, -1)
True
>>> two_equal(0, 0, 0)
False
"""
"*** YOUR CODE HERE ***"
if a == b:
return a != c
else:
return a == c or b == c
Question 5
If we list all the natural numbers below 10 that are multiples of 3 or 5, we
get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the
multiples of mor n below some number limit.
def sum_multiples(m, n, limit):
"""
>>> sum_multiples(3, 5, 10)
23
>>> sum_multiples(3, 7, 1000)
214216
"""
"*** YOUR CODE HERE ***"
count = 0
total = 0
while count < limit:
if count % m == 0 or count % n == 0:
total += count
count += 1
return total
Question 6
Implement the function ordered_digits, which takes as input a
positive integer and returns True if its digits, read left to right,
are in non-decreasing order, and False otherwise. For example, the
digits of 5, 11, 127, 1357 are ordered, but not those of 21 or 1375.
Hint: You can use // and % to separate a positive integer into
its one's digit and the rest of its digits.
def ordered_digits(x):
"""Return True if the (base 10) digits of X>0 are in non-decreasing
order, and False otherwise.
>>> ordered_digits(5)
True
>>> ordered_digits(11)
True
>>> ordered_digits(127)
True
>>> ordered_digits(1357)
True
>>> ordered_digits(21)
False
>>> result = ordered_digits(1375) # Return, don't print
>>> result
False
>>> cases = [(1, True), (9, True), (10, False), (11, True), (32, False),
... (23, True), (99, True), (111, True), (122, True), (223, True),
... (232, False), (999, True),
... (13334566666889, True), (987654321, False)]
>>> [ordered_digits(s) == t for s, t in cases].count(False)
0
"""
"*** YOUR CODE HERE ***"
last = x % 10
val = x // 10
while x > 0 and last >= x % 10:
last = x % 10
x = x // 10
return x == 0
We split off each digit in turn from the right, comparing it to the previous digit we split off, which was the one immediately to its right. We stop when we run out of digits or we find an out-of-order digit.
Higher order functions and Lambdas
Question 7: Intersect
Two functions intersect at an argument x if they return equal values.
Implement intersects, which takes a one-argument functions f and a value
x. It returns a function that takes another function g and returns whether
f and g intersect at x.
def intersects(f, x):
"""Returns a function that returns whether f intersects g at x.
>>> at_three = intersects(square, 3)
>>> at_three(triple) # triple(3) == square(3)
True
>>> at_three(increment)
False
>>> at_one = intersects(identity, 1)
>>> at_one(square)
True
>>> at_one(triple)
False
"""
"*** YOUR CODE HERE ***"
def at_x(g):
return f(x) == g(x)
return at_x
Question 8: Smooth
The idea of smoothing a function is an important concept in signal
processing. If f is a one-argument function and dx is some small
number, then the smoothed version of f is the function whose value at
a point x is the average of f(x - dx), f(x), and f(x + dx).
Write a function smooth that takes as input a function f and a
value to use for dx and returns a function that computes the smoothed
version of f. Do not use any def statements inside of smooth; use
lambda expressions instead.
def smooth(f, dx):
"""Returns the smoothed version of f, g where
g(x) = (f(x - dx) + f(x) + f(x + dx)) / 3
>>> square = lambda x: x ** 2
>>> round(smooth(square, 1)(0), 3)
0.667
"""
"*** YOUR CODE HERE ***"
return lambda x: (f(x - dx) + f(x) + f(x + dx)) / 3
Question 9
Draw the environment diagram for the following code:
x = 5
def compose1(f, g):
def h(x):
return f(g(x))
return h
d = lambda y: y * x
x = 4
result = compose1(lambda z: z - 1, d)(3)
There are 5 frames total (including the Global frame). In addition, consider the following questions:
- In frame
f1(the frame forcompose1), the parameterfpoints to a function object. What is the intrinsic name of that function object, and what frame is its parent? - In frame
f2, what name is the frame labeled with (hor λ)? Which frame is the parent off2? - In frame
f3, what name is the frame labeled with (f,g,d, or λ)? Which frame is the parent off3? In order to compute the return valuey * x, in which frame does Python findx? What is that value ofx? - In frame
f4, what name is the frame labeled with (f,g,d, or λ)? Which frame is the parent off3? - What value is the variable
resultbound to in the Global frame?
You can try out the environment diagram at tutor.cs61a.org.
- The intrinsic name of the function object that
fpoints to is λ (specifically, the lambda whose parameter isz). The parent frame of this lambda is Global. f2is labeled with the nameh; the parent frame off2isf1, since that is wherehis defined.f3is labeled with the name λ (specifically, it is the λ that takes in a parametery). The parent frame off3is Global, since that is where this lambda was defined (the lined = lambda y: y * x).f4is labeled with the name λ (specifically, it is the λ that takes a parameterz). The parent frame off4is Global, since that is where the lambda is defined.You might think that the parent of
f4isf1, sincelambda z: z - 1is being passed intocompose1. Remember, however, that operands are evaluated before the operator is applied (that is, before we create the framef1). Since we are evaluatinglambda z: z - 1in the Global frame, its parent is Global.- The variable
resultis bound to 11.