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
None
is 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
n
is larger than the ones digit of n
. For example,
Calling
ordered_two_digits
on these numbers will returnTrue
:- 52
- 1342
Calling
ordered_two_digits
on 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 m
or 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 parameterf
points 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 (h
or λ)? 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
result
bound to in the Global frame?
You can try out the environment diagram at tutor.cs61a.org.
- The intrinsic name of the function object that
f
points to is λ (specifically, the lambda whose parameter isz
). The parent frame of this lambda is Global. f2
is labeled with the nameh
; the parent frame off2
isf1
, since that is whereh
is defined.f3
is labeled with the name λ (specifically, it is the λ that takes in a parametery
). The parent frame off3
is Global, since that is where this lambda was defined (the lined = lambda y: y * x
).f4
is labeled with the name λ (specifically, it is the λ that takes a parameterz
). The parent frame off4
is Global, since that is where the lambda is defined.You might think that the parent of
f4
isf1
, sincelambda z: z - 1
is 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 - 1
in the Global frame, its parent is Global.- The variable
result
is bound to 11.