天天看点

CS 61A Spring 2019 HW01 学习笔记主要内容Q0: Welcome SurveyQ1: A Plus Abs BQ2: Two of ThreeQ3: Largest FactorQ4: If Function vs Statement

CS 61A: Structure and Interpretation of Computer Programs 课程官网

Homework 1: Control 作业链接 参考答案

主要内容

  1. 函数名称、函数调用;
  2. 运算符

    **

    //

  3. 纯函数与非纯函数。

Q0: Welcome Survey

Q1: A Plus Abs B

Fill in the blanks in the following function for adding

a

to the absolute value of

b

, without calling

abs

. You may not modify any of the provided code other than the two blanks.
from operator import add, sub

def a_plus_abs_b(a, b):
    """Return a+abs(b), but without calling abs.

    >>> a_plus_abs_b(2, 3)
    5
    >>> a_plus_abs_b(2, -3)
    5
    """
    if b < 0:
        f = _____
    else:
        f = _____
    return f(a, b)
           

我的解答(同参考答案):

if b < 0:
        f = sub
    else:
        f = add
    return f(a, b)
           

NOTE

在Python中,函数作为对象,可以有多个名称。赋值语句

f = sub

使名称

f

连接到

sub()

函数上。调用

f(a, b)

sub(a, b)

等价。

f = add

同理。

Q2: Two of Three

Write a function that takes three positive numbers and returns the sum of the squares of the two largest numbers. Use only a single line for the body of the function.
def two_of_three(a, b, c):
    """Return x*x + y*y, where x and y are the two largest members of the
    positive numbers a, b, and c.

    >>> two_of_three(1, 2, 3)
    13
    >>> two_of_three(5, 3, 1)
    34
    >>> two_of_three(10, 2, 8)
    164
    >>> two_of_three(5, 5, 5)
    50
    """
    return _____
           

我的解答:

参考答案:

return max(a*a+b*b, a*a+c*c, b*b+c*c)
    # Alternate solution
    return a**2 + b**2 + c**2 - min(a, b, c)**2
           

两种思路:

  1. 正向考虑,首先计算出所有可能的情况,再选出其中最大的,如参考答案第1条所示。这里主要使用了平方不改变正数相对大小的性质。
  2. 反向考虑,找到3个数中最小值,从平方和中减去最小值的平方。在输入存在负数时,这种方法依然可用。

NOTE

a**2 == pow(a, 2) == a*a
           

Q3: Largest Factor

Write a function that takes an integer

n

that is greater than 1 and returns the largest integer that is smaller than

n

and evenly divides

n

.
def largest_factor(n):
    """Return the largest factor of n that is smaller than n.

    >>> largest_factor(15) # factors are 1, 3, 5
    5
    >>> largest_factor(80) # factors are 1, 2, 4, 5, 8, 10, 16, 20, 40
    40
    >>> largest_factor(13) # factor is 1 since 13 is prime
    1
    """
    "*** YOUR CODE HERE ***"
           

我的解答:

i = 2
    while i <= n ** 0.5:
        if n % i:
            i += 1
        else:
            return int(n / i)    
    return 1
           

参考答案:

factor = n - 1
    while factor > 0:
        if n % factor == 0:
            return factor
        factor -= 1
           

注意到

>>> largest_factor(15)
    5  # 3 * 5 = 15
    >>> largest_factor(80)
    40  # 2 * 40 = 80
    >>> largest_factor(13)
    1  # 1 * 13 = 13
           

因此对于质数以外的输入,从2开始向上遍历可以以较少的迭代次数得到结果。此外,循环的终止条件为

i ** 2 > n

,因为因子总是成对出现的。使用上述特性,可以减少循环次数,这是我的解答的思路。

相比之下,参考答案更为直观、简洁,只用了1个

return

NOTE

n % i == 0

的条件下执行

return int(n / i)

,此时

int(n / i)

可用

n // i

代替。参考:

>>> 6 / 2
3.0  # float
>>> 6 // 2
3  # int
>>> 6.0 // 2
3.0
>>> 6.5 / 2
3.25
>>> 6.5 // 2
3.0
           

Q4: If Function vs Statement

def if_function(condition, true_result, false_result):
    """Return true_result if condition is a true value, and
    false_result otherwise.

    >>> if_function(True, 2, 3)
    2
    >>> if_function(False, 2, 3)
    3
    >>> if_function(3==2, 3+2, 3-2)
    1
    >>> if_function(3>2, 3+2, 3-2)
    5
    """
    if condition:
        return true_result
    else:
        return false_result


def with_if_statement():
    """
    >>> result = with_if_statement()
    2
    >>> print(result)
    None
    """
    if c():
        return t()
    else:
        return f()

def with_if_function():
    """
    >>> result = with_if_function()
    1
    2
    >>> print(result)
    None
    """
    return if_function(c(), t(), f())

def c():
    "*** YOUR CODE HERE ***"

def t():
    "*** YOUR CODE HERE ***"

def f():
    "*** YOUR CODE HERE ***"
           

我的解答(同参考答案):

def c():
    return False

def t():
    print(1)

def f():
    print(2)
           

NOTE

这道题的重点是,在执行

return if_function(c(), t(), f())

时,解释器会首先计算3个函数,并将函数返回值作为参数传入

if_function

c()

的返回值不会影响

t()

f()

的执行。

如果修改代码:

def if_function(condition, true_result, false_result):
    if condition:
        return true_result()
    else:
        return false_result()

def with_if_statement():
    if c():
        return t()
    else:
        return f()

def with_if_function():
    return if_function(c(), t, f)
           

将函数名作为参数传入

if_function()

,在函数内计算。此时

with_if_statement()

with_if_function()

的结果一致。因此在编码时要注意函数参数传递的是函数名还是函数。

这道题的另一个关键点在于,

print()

是一个非纯函数(non-pure function),导致

t()

f()

也是非纯函数。与之对应的概念是纯函数(pure function),例如

max()

pow()

abs()

等。

Pure functions are restricted in that they cannot have side effects or change behavior over time. Imposing these restrictions yields substantial benefits. First, pure functions can be composed more reliably into compound call expressions. We can see in the non-pure function example above that print does not return a useful result when used in an operand expression. On the other hand, we have seen that functions such as max, pow and sqrt can be used effectively in nested expressions.

CS 61A Textbook Ch. 1.2

非纯函数会带来副作用(side effect),对于

print()

而言,它会在标准输出上打印文字。因此,对于嵌套表达式,例如

if_function(c(), t(), f())

,使用纯函数作为操作数(operand)会更好。如果这样修改代码:

def t():
    return 1

def f():
    return 2
           

with_if_statement()

with_if_function()

的结果一致,因为此时

t()

f()

是纯函数。

Q5: Hailstone

This sequence of values of

n

is often called a Hailstone sequence. Write a function that takes a single argument with formal parameter name

n

, prints out the hailstone sequence starting at

n

, and returns the number of steps in the sequence:
def hailstone(n):
    """Print the hailstone sequence starting at n and return its
    length.

    >>> a = hailstone(10)
    10
    5
    16
    8
    4
    2
    1
    >>> a
    7
    """
    "*** YOUR CODE HERE ***"
           

我的解答:

count = 0
    while n > 1:
        print(int(n))
        count += 1
        if n % 2:  # odd
            n = n * 3 + 1
        else:  # even
            n /= 2
    print(int(n))
    count += 1
    return count
           

参考答案:

length = 1
    while n != 1:
        print(n)
        if n % 2 == 0:
            n = n // 2      # Integer division prevents "1.0" output
        else:
            n = 3 * n + 1
        length = length + 1
    print(n)                # n is now 1
    return length