实验1: 变量和函数,控制结构
Lab 1: Variables & Functions, Control

Due by 11:59pm on Tuesday, September 1.

查看英文原文

初始文件

下载 lab01.zip。 在压缩包中,你会找到本实验问题的初始文件, 以及一份 Ok 自动评分器。

另外,请填写 这份调查问卷,告知我们你在实验0中遇到的任何问题,或者你是否使用了Windows自动安装程序。

为了快速生成ok命令,你现在可以使用 ok命令生成器

快速检查

使用 Python

在运行Python文件时,你可以使用命令行选项进一步检查你的代码。 以下是一些有用的选项。 如果你想了解更多关于其他Python命令行选项的信息,可以查看 此文档

  • 不使用任何命令行选项:这将运行你提供的文件中的代码,并返回到命令行。

    python3 foo.py
  • -i-i选项会运行你的 Python 脚本,然后打开一个交互式会话。 在交互式会话中,你可以逐行运行 Python 代码,并实时得到结果,而不是一次性运行整个文件。 你可以输入exit()来退出。也可以使用 Linux/Mac 系统中的快捷键Ctrl-D 或者 Windows 系统中的Ctrl-Z Enter来退出。

    如果在交互模式下运行 Python 文件时编辑了文件,你需要退出并重新启动解释器,才能让更改生效。

    python3 -i foo.py
  • -m doctest:在特定文件中运行doctests。 doctests可用于测试函数中用三引号(""")包裹的测试样例。

    文件中的每个测试都由 >>> 开头, 后跟一些 Python 代码和预期的输出(不过 >>> 不会出现在 doctest 命令的输出中)。

     python3 -m doctest foo.py

使用OK

在 CS61A 课程中,我们使用 Ok 来对实验、作业和项目进行自动评分。在本实验的初始文件中,你应该已经下载了 Ok。要了解更多关于 Ok 命令的使用信息,请点击这里.

你可以在 links.cs61a.org/ok-help 快速生成大多数 Ok 命令!

要使用 Ok 运行指定函数的 doctest,请运行以下命令:

python3 ok -q <指定函数名> --local

默认情况下,只有未通过的测试会显示出来。你可以使用 -v 选项来查看所有测试,包括你已通过的测试:

python3 ok -v

你还可以在 Ok 中使用调试打印功能,方法如下:

print("DEBUG:", x)

最后,当你完成了 lab01.py 中的所有问题后,必须使用 --submit 选项提交作业:

python3 ok --submit

要了解更多 Ok 命令,请访问这里.

主要内容

如果你需要复习本实验的内容,请参考这一部分。你也可以直接跳到问题部分,遇到困难时再回来看这里。

Division

Let's compare the different division-related operators in Python 3:

True Division: /
(decimal division)
Floor Division: //
(integer division)
Modulo: %
(remainder)
>>> 1 / 5
0.2

>>> 25 / 4
6.25

>>> 4 / 2
2.0

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

>>> 25 // 4
6

>>> 4 // 2
2

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

>>> 25 % 4
1

>>> 4 % 2
0

>>> 5 % 0
ZeroDivisionError

Notice that Python outputs ZeroDivisionError for certain cases. We will go over this later in this lab under Error Messages.

One useful technique involving the % operator is to check whether a number x is divisible by another number y:

x % y == 0

For example, in order to check if x is an even number:

x % 2 == 0

Functions

If we want to execute a series of statements over and over, we can abstract them away into a function to avoid repeating code.

For example, let's say we want to know the results of multiplying the numbers 1-3 by 3 and then adding 2 to it. Here's one way to do it:

>>> 1 * 3 + 2
5
>>> 2 * 3 + 2
8
>>> 3 * 3 + 2
11

If we wanted to do this with a larger set of numbers, that'd be a lot of repeated code! Let's write a function to capture this operation given any input number.

def foo(x):
    return x * 3 + 2

This function, called foo, takes in a single argument and will return the result of multiplying that argument by 3 and adding 2.

Now we can call this function whenever we want this operation to be done:

>>> foo(1)
5
>>> foo(2)
8
>>> foo(1000)
3002

Applying a function to some arguments is done with a call expression.

Call expressions

A call expression applies a function, which may or may not accept arguments. The call expression evaluates to the function's return value.

The syntax of a function call:

  add   (    2   ,    3   )
   |         |        |
operator  operand  operand

Every call expression requires a set of parentheses delimiting its comma-separated operands.

To evaluate a function call:

  1. Evaluate the operator, and then the operands (from left to right).
  2. Apply the operator to the operands (the values of the operands).

If an operand is a nested call expression, then these two steps are applied to that inner operand first in order to evaluate the outer operand.

return and print

Most functions that you define will contain a return statement. The return statement will give the result of some computation back to the caller of the function and exit the function. For example, the function square below takes in a number x and returns its square.

def square(x):
    """
    >>> square(4)
    16
    """
    return x * x

When Python executes a return statement, the function terminates immediately. If Python reaches the end of the function body without executing a return statement, it will automatically return None.

In contrast, the print function is used to display values in the Terminal. This can lead to some confusion between print and return because calling a function in the Python interpreter will print out the function's return value.

However, unlike a return statement, when Python evaluates a print expression, the function does not terminate immediately.

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

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

Notice also that print will display text without the quotes, but return will preserve the quotes.


Control

Boolean Operators

Python supports three boolean operators: and, or, and not:

>>> a = 4
>>> a < 2 and a > 0
False
>>> a < 2 or a > 0
True
>>> not (a > 0)
False
  • and evaluates to True only if both operands evaluate to True. If at least one operand is False, then and evaluates to False.
  • or evaluates to True if at least one operand evaluates to True. If both operands are False, then or evaluates to False.
  • not evaluates to True if its operand evaluates to False. It evaluates to False if its operand evalutes to True.

What do you think the following expression evaluates to? Try it out in the Python interpreter.

>>> True and not False or not True and False

It is difficult to read complex expressions, like the one above, and understand how a program will behave. Using parentheses can make your code easier to understand. Python interprets that expression in the following way:

>>> (True and (not False)) or ((not True) and False)

This is because boolean operators, like arithmetic operators, have an order of operation:

  • not has the highest priority
  • and
  • or has the lowest priority

Truthy and Falsey Values: It turns out and and or work on more than just booleans (True, False). Python values such as 0, None, '' (the empty string), and [] (the empty list) are considered false values. All other values are considered true values.

Short Circuiting

What do you think will happen if we type the following into Python?

1 / 0

Try it out in Python! You should see a ZeroDivisionError. But what about this expression?

True or 1 / 0

It evaluates to True because Python's and and or operators short-circuit. That is, they don't necessarily evaluate every operand.

Operator Checks if: Evaluates from left to right up to: Example
AND All values are true The first false value False and 1 / 0 evaluates to False
OR At least one value is true The first true value True or 1 / 0 evaluates to True

Short-circuiting happens when the operator reaches an operand that allows them to make a conclusion about the expression. For example, and will short-circuit as soon as it reaches the first false value because it then knows that not all the values are true.

If and and or do not short-circuit, they just return the last value; another way to remember this is that and and or always return the last thing they evaluate, whether they short circuit or not. Keep in mind that and and or don't always return booleans when using values other than True and False.

If Statements

You can review the syntax of if statements in Section 1.5.4 of Composing Programs.

Tip: We sometimes see code that looks like this:

if x > 3:
    return True
else:
    return False

This can be written more concisely as return x > 3. If your code looks like the code above, see if you can rewrite it more clearly!

While Loops

You can review the syntax of while loops in Section 1.5.5 of Composing Programs.


Error Messages

By now, you've probably seen a couple of error messages. They might look intimidating, but error messages are very helpful for debugging code. The following are some common types of errors:

Error Types Descriptions
SyntaxError Contained improper syntax (e.g. missing a colon after an if statement or forgetting to close parentheses/quotes)
IndentationError Contained improper indentation (e.g. inconsistent indentation of a function body)
TypeError Attempted operation on incompatible types (e.g. trying to add a function and a number) or called function with the wrong number of arguments
ZeroDivisionError Attempted division by zero

Using these descriptions of error messages, you should be able to get a better idea of what went wrong with your code. If you run into error messages, try to identify the problem before asking for help. You can often Google unfamiliar error messages to see if others have made similar mistakes to help you debug.

For example:

>>> square(3, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: square() takes 1 positional argument but 2 were given

Note:

  • The last line of an error message tells us the type of the error. In the example above, we have a TypeError.
  • The error message tells us what we did wrong -- we gave square 2 arguments when it can only take in 1 argument. In general, the last line is the most helpful.
  • The second to last line of the error message tells us on which line the error occurred. This helps us track down the error. In the example above, TypeError occurred at line 1.

必答题

Python会输出什么? (Part 1)

Q1: WWPD: 控制

使用 Ok 的 "Python会输出什么?" 的题目来测试你的学习成果:

python3 ok -q control -u --local

提示: 确保你的 while 循环的判断条件最终为 False ,不然你的程序将进入死循环。 按 Ctrl-C 来停止

>>> def xk(c, d):
...     if c == 4:
...         return 6
...     elif d >= 4:
...         return 6 + 7 + c
...     else:
...         return 25
>>> xk(10, 10)
______
23
>>> xk(10, 6)
______
23
>>> xk(4, 6)
______
6
>>> xk(0, 0)
______
25
>>> def how_big(x):
...     if x > 10:
...         print('huge')
...     elif x > 5:
...         return 'big'
...     elif x > 0:
...         print('small')
...     else:
...         print("nothin")
>>> how_big(7)
______
'big'
>>> how_big(12)
______
huge
>>> how_big(1)
______
small
>>> how_big(-1)
______
nothin
>>> n = 3
>>> while n >= 0:
...     n -= 1
...     print(n)
______
2 1 0 -1
>>> positive = 28
>>> while positive:
...    print("positive?")
...    positive -= 3
______
Infinite Loop
>>> positive = -9
>>> negative = -12
>>> while negative:
...    if positive:
...        print(negative)
...    positive += 3
...    negative += 3
______
-12 -9 -6

Q2: WWPD: 值的真假

使用 Ok 的 "Python会输出什么?" 的题目来测试你的学习成果:

python3 ok -q short-circuit -u --local
>>> True and 13
______
13
>>> False or 0
______
0
>>> not 10
______
False
>>> not None
______
True
>>> True and 1 / 0 and False
______
Error (ZeroDivisionError)
>>> True or 1 / 0 or False
______
True
>>> True and 0
______
0
>>> False or 1
______
1
>>> 1 and 3 and 6 and 10 and 15
______
15
>>> -1 and 1 > 0
______
True
>>> 0 or False or 2 or 1 / 0
______
2
>>> not 0
______
True
>>> (1 + 1) and 1
______
1
>>> 1/0 or True
______
Error
>>> (True or False) and False
______
False

Q3: 调试测验!

以下是一个关于本课程中应使用的不同调试技巧的快速测验。你应该参考此文档来回答问题!

运行以下命令开始测验:

python3 ok -q debugging-quiz -u --local

编程练习

Q4: 递减阶乘

让我们编写一个函数 falling, 它是一个“递减”阶乘函数,接受两个参数 nk,并返回从 n 开始,向下递减的 k 个连续数字的乘积。

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 --local

Q5: 数位之和

编写一个函数,该函数接受一个非负整数并计算其各位数字的和。(使用取整除法和取模运算可能会对你有帮助!)

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 --local

Submit

Make sure to submit this assignment by running:

python3 ok --submit

Reminder: Please fill out the Lab 0 survey (also included at the beginning of this assignment): this survey

扩展练习

这些问题是可选的,不会影响你在本次作业中的分数。 然而,它们对于未来的作业、项目和考试是很好的练习。 尝试这些问题对巩固你对课程概念和理解非常有帮助,而且它们很有趣!

Python会输出什么?(Part 2)

Q6: WWPD: 条件判断

使用 Ok 的"Python会输出什么?"的题目来测试你的学习成果:

python3 ok -q if-statements -u --local

提示: 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'

扩展编程练习

Q7: 双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 --local