实验 1:函数与控制

截止时间:6 月 25 日(星期四)晚上 11:59。

起始文件

下载 lab01.zip.

出勤要求

要获得实验课学分,除了到场参加实验课外,你还需要提交实验题目。

如果你因合理原因(例如生病或时间冲突)缺席实验课,或者由于某种原因未能完成签到,请在一周内发送邮件至 cs61a@berkeley.edu ,以补记出勤学分。

必做题

知识回顾

Important: 如果 python3 命令无法运行,请尝试使用 pythonpy.

下面是使用 Python 运行文件最常见的几种方式。
  1. 不带任何命令行选项时,Python 会运行指定文件中的代码,然后返回命令行。如果文件只包含函数定义,除非存在语法错误,否则不会看到任何输出。

    python3 lab00.py
  2. -i-i 选项会先运行指定文件中的代码,再打开一个交互式会话(显示 >>> 提示符)。随后你可以对表达式求值,例如调用自己定义的函数。要退出,请输入 exit()。也可以使用键盘快捷键 Ctrl-D (Linux/Mac)或 Ctrl-Z Enter (Windows)。

    如果在交互式运行期间修改了 Python 文件,需要退出并重新启动解释器,修改才会生效。

    下面演示如何以交互方式运行 lab00.py

    python3 -i lab00.py
  3. -m doctest:运行文件中的 doctest,也就是函数文档字符串里的示例。

    文件中的每个测试都由 >>> 开头,后面跟着一段 Python 代码和预期输出。

    下面演示如何运行文件中的 doctest: lab00.py:

     python3 -m doctest lab00.py

    如果代码通过所有 doctest,终端不会显示任何输出;否则会显示未通过测试的详细信息。


在 CS 61A 中,我们使用名为 Ok 的程序对实验、家庭作业和项目进行自动评分。

要用 Ok 测试某个函数,请运行以下命令(把 FUNCTION 替换为函数名):

python3 ok -q FUNCTION

如果函数中调用了 print ,并且输出内容以 "DEBUG:"开头,Ok 会忽略这一行。(否则,多余的 print 调用会产生额外输出,从而导致测试失败。)

print("DEBUG:", x)

更多功能请参阅 “使用 Ok”页面. 你也可以在这里快速生成大多数 Ok 命令: ok-help.


下面是 Python 3 中与除法有关的运算符示例:

真除法: /
(小数除法)
整除: //
(向下取整除法)
取模: %
(余数)
>>> 1 / 5
0.2

>>> 25 / 4
6.25

>>> 4 / 2
2.0

>>> 5 / 0
ZeroDivisionError
>>> 1 // 5 # truncate result of true division
0

>>> 25 // 4
6

>>> 4 // 2
2

>>> 5 // 0
ZeroDivisionError
>>> 1 % 5
1

>>> 25 % 4
1

>>> 4 % 2
0

>>> 5 % 0
ZeroDivisionError

除以 0 时会发生 ZeroDivisionError

取模运算符有一个很实用的用途:检查一个数 % 是否能被另一个数 x 整除。 y:

x % y == 0

例如,要检查 x 是否为偶数,可以这样写: x % 2 == 0


你定义的大多数函数都会包含一条 return 语句,用来提供函数调用表达式的值。

当 Python 执行 return 语句时,函数调用会立即结束。如果 Python 运行到函数体末尾仍未执行 return 语句,函数将返回 None.

相比之下, print 函数用于显示值。与 return 语句不同,Python 对 print调用求值时,函数 不会 立即结束。

def what_prints():
    print('Hello World!')
    return 'Exiting this function.'
    print('This course is awesome!')

>>> what_prints()
Hello World!
'Exiting this function.'

还要注意, print 显示文本时 不会带引号,而 return 会保留引号。

Python 会显示什么?(WWPD)

问题 1:Return 与 Print

使用 Ok 完成下面的“Python 会显示什么?”(WWPD)题,检查你对知识的掌握情况:

python3 ok -q return-and-print -u

>>> def welcome():
...     print('Go')
...     return 'hello'
...
>>> def cal():
...     print('Bears')
...     return 'world'
...
>>> welcome()
______
Go 'hello'
>>> print(welcome(), cal())
______
Go Bears hello world

问题 2:WWPD——如果这样呢?

使用 Ok 完成下面的“Python 会显示什么?”(WWPD)题,检查你对知识的掌握情况:

python3 ok -q if-statements -u

提示: print (不同于 return),它会 不会 使函数退出。

>>> def ab(c, d):
...     if c > 5:
...         print(c)
...     elif c > 7:
...         print(d)
...     print('foo')
>>> ab(10, 20)
______
10 foo
>>> def bake(cake, make):
...     if cake == 0:
...         cake = cake + 1
...         print(cake)
...     if cake == 1:
...         print(make)
...     else:
...         return cake
...     return make
>>> bake(0, 29)
______
1 29 29
>>> bake(1, "mashed potatoes")
______
mashed potatoes 'mashed potatoes'

编写代码

问题 3:调试小测

下面是一份关于不同调试技巧的小测,这些技巧会在本课程中派上用场。答题时可以参考 调试指南

使用 Ok 检查你的理解:

python3 ok -q debugging-quiz -u

问题 4:下降阶乘

请编写函数 falling,它计算“下降阶乘”,接收两个参数 nk,并返回从 k 开始向下连续 n 个整数的乘积。当 k 为 0 时,函数应返回 1。

def falling(n, k):
    """Compute the falling factorial of n to depth k.

    >>> falling(6, 3)  # 6 * 5 * 4
    120
    >>> falling(4, 3)  # 4 * 3 * 2
    24
    >>> falling(4, 1)  # 4
    4
    >>> falling(4, 0)
    1
    """
    "*** YOUR CODE HERE ***"

使用 Ok 测试你的代码:

python3 ok -q falling

问题 5:能被 k 整除

请编写函数 divisible_by_k ,它接收正整数 nk。该函数按从小到大的顺序,打印所有不大于 n 且能被 k 整除的正整数,最后返回所打印数字的数量。

def divisible_by_k(n, k):
    """
    >>> a = divisible_by_k(10, 2)  # 2, 4, 6, 8, and 10 are divisible by 2
    2
    4
    6
    8
    10
    >>> a
    5
    >>> b = divisible_by_k(3, 1)  # 1, 2, and 3 are divisible by 1
    1
    2
    3
    >>> b
    3
    >>> c = divisible_by_k(6, 7)  # There are no integers up to 6 that are divisible by 7
    >>> c
    0
    """
    "*** YOUR CODE HERE ***"

使用 Ok 测试你的代码:

python3 ok -q divisible_by_k

问题 6:连续两个 8

请编写一个接收数字的函数,判断它的十进制数位中是否包含两个相邻的 8。

def double_eights(n):
    """Return true if n has two eights in a row.
    >>> double_eights(8)
    False
    >>> double_eights(88)
    True
    >>> double_eights(2882)
    True
    >>> double_eights(880088)
    True
    >>> double_eights(12345)
    False
    >>> double_eights(80808080)
    False
    """
    "*** YOUR CODE HERE ***"

使用 Ok 测试你的代码:

python3 ok -q double_eights

课程大纲小测

问题 7:课程大纲小测

请填写 课程大纲小测,以确认你已经理解课程大纲页面中的各项规定。

在本地检查得分

你可以运行以下命令,在本地检查本次作业每道题的得分:

python3 ok --score

这不会提交作业! 确认得分符合预期后,请将作业提交到 Gradescope,以获得作业学分。

提交作业

请上传所有你修改过的文件,将本次作业提交到 对应的 Gradescope 作业入口。 Lab 00 中提供了详细说明。

正确完成所有题目可得 1 分。 Please ensure your TA has taken your attendance before leaving.

可选题

以下题目为选做题。即使不完成,你仍能获得本次作业的学分;不过它们很适合用来练习,建议还是做一做!

问题 8:选取一个数位

请实现 digit,它接收正整数 nk ,且函数体只能包含一条 return 语句。它应返回 n 中位于最右侧数位(个位)左边第 k 位的数字。如果 k 为 0,则返回最右侧数位;如果不存在位于其左边第 n 中位于最右侧数位(个位)左边第 k 位的数字,则返回 0。

Hint: 可以使用 //% 以及内置 pow 函数来取出 n.

def digit(n, k):
    """Return the k-th digit from the right of n for positive integers n and k.

    >>> digit(3579, 2)
    5
    >>> digit(3579, 0)
    9
    >>> digit(3579, 10)
    0
    """
    return ____

使用 Ok 测试你的代码:

python3 ok -q digit

问题 9:中间大小的数

请实现 middle :只写一个 return 表达式,返回三个互不相同的整数中既不是最大值、也不是最小值的那个数 abc.

Hint: 可以先把所有数合在一起,再利用内置 minmax 函数减去不需要返回的数。

>>> max(1, 2, 3)
3
>>> min(-1, -2, -3)
-3
def middle(a, b, c):
    """Return the number among a, b, and c that is not the smallest or largest.
    Assume a, b, and c are all different numbers.

    >>> middle(3, 5, 4)
    4
    >>> middle(30, 5, 4)
    5
    >>> middle(3, 5, 40)
    5
    >>> middle(3, 5, 40)
    5
    >>> middle(30, 5, 40)
    30
    """
    return ____

使用 Ok 测试你的代码:

python3 ok -q middle

问题 10:数位求和

请编写一个函数,接收非负整数并返回其各个数位之和。(整除和取模运算在这里可能很有帮助!)

def sum_digits(y):
    """Sum all the digits of y.

    >>> sum_digits(10) # 1 + 0 = 1
    1
    >>> sum_digits(4224) # 4 + 2 + 2 + 4 = 12
    12
    >>> sum_digits(1234567890)
    45
    >>> a = sum_digits(123) # make sure that you are using return rather than print
    >>> a
    6
    """
    "*** YOUR CODE HERE ***"

使用 Ok 测试你的代码:

python3 ok -q sum_digits