Chapter 5 Conditionals and recursion 第 5 章 条件与递归
本页译自 Think Python 2e(Allen B. Downey)· Chapter 5 Conditionals and recursion。代码块保留英文原文不翻译;正文段段对照,中文块可用右下角按钮隐藏。
5.1 Modulus operator 5.1 取模运算符
The modulus operator works on integers and yields the remainder when the first operand is divided by the second. In Python, the modulus operator is a percent sign (%). The syntax is the same as for other operators:
%)。它的语法与其他运算符相同:%00000006
So 7 divided by 3 is 2 with 1 left over.
The modulus operator turns out to be surprisingly useful. For example, you can check whether one number is divisible by another—if %0000 is zero, then % is divisible by %.
%0000 为零,那么 % 能被 % 整除。Also, you can extract the right-most digit or digits from a number. For example, %00000 yields the right-most digit of % (in base 10). Similarly %000000 yields the last two digits.
%00000 给出 % 的最右一位(以十进制计)。类似地,%000000 给出最后两位。5.2 Boolean expressions 5.2 布尔表达式
A boolean expression is an expression that is either true or false. The following examples use the operator %0, which compares two operands and produces %000 if they are equal and %0000 otherwise:
%0,它比较两个操作数:若相等则产生 %000,否则产生 %0000:%00000025
%000 and %0000 are special values that belong to the type %000; they are not strings:
%000 和 %0000 是特殊的值,属于 %000 类型;它们不是字符串:%00000032
The %0 operator is one of the relational operators; the others are:
%0 运算符是关系运算符之一;其余的如下:%00000035
Although these operations are probably familiar to you, the Python symbols are different from the mathematical symbols. A common error is to use a single equal sign (%) instead of a double equal sign (%0). Remember that % is an assignment operator and %0 is a relational operator. There is no such thing as %0000 or %0000.
%)代替双等号(%0)。记住,% 是赋值运算符,而 %0 是关系运算符。不存在 %0000 或 %0000 这样的东西。5.3 Logical operators 5.3 逻辑运算符
There are three logical operators: %00, %0, and %00. The semantics (meaning) of these operators is similar to their meaning in English. For example, %00000051 is true only if % is greater than 0 and less than 10.
%00、%0 和 %00。这些运算符的语义(含义)与它们在英语中的意思相近。例如,%00000056 仅当 % 大于 0 且小于 10 时才为真。%00000058 is true if either of the conditions is true, that is, if the number is divisible by 2 or 3.
%00000059 在两个条件中任一为真时为真,也就是说,当该数能被 2 或 3 整除时为真。Finally, the %00 operator negates a boolean expression, so %00000061 is true if %0000006 is false, that is, if % is less than or equal to %.
%00 运算符对布尔表达式取反,所以 %00000066 在 %0000006 为假时为真,也就是说,当 % 小于或等于 % 时为真。Strictly speaking, the operands of the logical operators should be boolean expressions, but Python is not very strict. Any nonzero number is interpreted as "true."
%00000070
This flexibility can be useful, but there are some subtleties to it that might be confusing. You might want to avoid it (unless you know what you are doing).
5.4 Conditional execution 5.4 条件执行
In order to write useful programs, we almost always need the ability to check conditions and change the behavior of the program accordingly. Conditional statements give us this ability. The simplest form is the %0 statement:
%0 语句:%00000073
The boolean expression after %0 is called the condition. If it is true, then the indented statement gets executed. If not, nothing happens.
%0 之后的布尔表达式称为条件。若为真,则缩进的语句会被执行;否则什么也不会发生。%0 statements have the same structure as function definitions: a header followed by an indented body. Statements like this are called compound statements.
%0 语句与函数定义结构相同:一个头部,后跟一个缩进的主体。这样的语句称为复合语句。There is no limit on the number of statements that can appear in the body, but there has to be at least one. Occasionally, it is useful to have a body with no statements (usually as a place keeper for code you haven’t written yet). In that case, you can use the %000 statement, which does nothing.
%000 语句,它什么也不做。%00000080
5.5 Alternative execution 5.5 二选一执行
A second form of the %0 statement is alternative execution, in which there are two possibilities and the condition determines which one gets executed. The syntax looks like this:
%0 语句的第二种形式是二选一执行,其中有两种可能,由条件决定执行哪一个。语法如下:%00000083
If the remainder when % is divided by 2 is 0, then we know that % is even, and the program displays a message to that effect. If the condition is false, the second set of statements is executed. Since the condition must be true or false, exactly one of the alternatives will be executed. The alternatives are called branches, because they are branches in the flow of execution.
% 除以 2 的余数等于 0,我们就知道 % 是偶数,程序会显示相应的信息。如果条件为假,则执行第二组语句。由于条件非真即假,两种可能中恰好有一种会被执行。这些可能称为分支,因为它们是执行流中的分支。5.6 Chained conditionals 5.6 链式条件
Sometimes there are more than two possibilities and we need more than two branches. One way to express a computation like that is a chained conditional:
%00000088
%000 is an abbreviation of "else if." Again, exactly one branch will be executed. There is no limit on the number of %000 statements. If there is an %000 clause, it has to be at the end, but there doesn’t have to be one.
%000 是「else if」的缩写。同样,恰好有一个分支会被执行。%000 语句的数量没有限制。如果有 %000 子句,它必须放在最后,但也可以没有。%00000095
Each condition is checked in order. If the first is false, the next is checked, and so on. If one of them is true, the corresponding branch executes, and the statement ends. Even if more than one condition is true, only the first true branch executes.
5.7 Nested conditionals 5.7 嵌套条件
One conditional can also be nested within another. We could have written the trichotomy example like this:
%00000096
The outer conditional contains two branches. The first branch contains a simple statement. The second branch contains another %0 statement, which has two branches of its own. Those two branches are both simple statements, although they could have been conditional statements as well.
%0 语句,它自身又有两个分支。那两个分支都是简单语句,不过它们同样可以是条件语句。Although the indentation of the statements makes the structure apparent, nested conditionals become difficult to read very quickly. In general, it is a good idea to avoid them when you can.
Logical operators often provide a way to simplify nested conditional statements. For example, we can rewrite the following code using a single conditional:
%00000099
The %0000 statement is executed only if we make it past both conditionals, so we can get the same effect with the %00 operator:
%0000 语句只有在两个条件都通过时才会执行,因此我们可以借助 %00 运算符获得同样的效果:%00000104
5.8 Recursion 5.8 递归
It is legal for one function to call another; it is also legal for a function to call itself. It may not be obvious why that is a good thing, but it turns out to be one of the most magical things a program can do. For example, look at the following function:
%00000105
If % is 0 or negative, it outputs the word, "Blastoff!" Otherwise, it outputs % and then calls a function named %00000108—itself—passing %00 as an argument.
% 为 0 或负数,它输出「Blastoff!」这个词。否则,它输出 %,然后调用一个名为 %00000112 的函数——也就是它自己——并把 %00 作为参数传入。What happens if we call this function like this?
%00000114
The execution of %00000115 begins with %00, and since % is greater than 0, it outputs the value 3, and then calls itself...
%00000118 的执行从 %00 开始,由于 % 大于 0,它输出值 3,然后调用自身……The execution of
%00000121 begins with%00, and since%is greater than 0, it outputs the value 2, and then calls itself...这次%00000124 的执行从%00 开始,由于%大于 0,它输出值 2,然后调用自身……The execution of
%00000127 begins with%00, and since%is greater than 0, it outputs the value 1, and then calls itself...这次%00000130 的执行从%00 开始,由于%大于 0,它输出值 1,然后调用自身……The execution of
%00000133 begins with%00, and since%is not greater than 0, it outputs the word, "Blastoff!" and then returns.这次%00000136 的执行从%00 开始,由于%不大于 0,它输出「Blastoff!」这个词,然后返回。The
%00000139 that got%00 returns.拿到%00 的那次%00000142 返回。The
%00000143 that got%00 returns.拿到%00 的那次%00000146 返回。
The %00000147 that got %00 returns. And then you’re back in %0000014. So, the total output looks like this:
%00 的那次 %00000151 返回。然后你就回到了 %0000015。于是,整体输出如下:%00000153
A function that calls itself is recursive; the process is called recursion.
As another example, we can write a function that prints a string % % times.
% 打印 % 次。%00000158
If %00000159 the %00000 statement exits the function. The flow of execution immediately returns to the caller, and the remaining lines of the function are not executed.
%00000161,%00000 语句会退出函数。执行流立即返回到调用者,函数中剩余的行不再执行。The rest of the function is similar to %00000163: if % is greater than 0, it displays % and then calls itself to display % n−1 additional times. So the number of lines of output is %00000167 , which adds up to %.
%00000169 类似:如果 % 大于 0,它就显示 %,然后调用自身再显示 % 共 n−1 次。所以输出的行数是 %00000173 ,相加等于 %。For simple examples like this, it is probably easier to use a %00 loop. But we will see examples later that are hard to write with a %00 loop and easy to write with recursion, so it is good to start early.
%00 循环或许更轻松。但稍后我们会看到一些用 %00 循环很难写、用递归却很容易的例子,所以早点开始是件好事。5.9 Stack diagrams for recursive functions 5.9 递归函数的栈图
In Section 3.10, we used a stack diagram to represent the state of a program during a function call. The same kind of diagram can help interpret a recursive function.
Every time a function gets called, Python creates a new function frame, which contains the function’s local variables and parameters. For a recursive function, there might be more than one frame on the stack at the same time.
Figure 5.1 shows a stack diagram for %00000179 called with %0000.
%0000 调用 %00000182 时的栈图。Figure 5.1: Stack diagram.
As usual, the top of the stack is the frame for %0000018. It is empty because we did not create any variables in %0000018 or pass any arguments to it.
%0000018 的栈帧。它是空的,因为我们没有在 %0000018 中创建任何变量,也没有向它传入任何参数。The four %00000187 frames have different values for the parameter %. The bottom of the stack, where %00, is called the base case. It does not make a recursive call, so there are no more frames.
%00000190 栈帧中,形参 % 的值各不相同。栈底(%00 处)称为基础情形。它不再进行递归调用,因此没有更多栈帧。Exercise 1 Draw a stack diagram for %000001 called with %00000194 and %00.
%00000196 、%00 调用 %000001 时的栈图。Exercise 2 Write a function called %000 that takes a function object and a number, %, as arguments, and that calls the given function % times.
%000 的函数,它接受一个函数对象和一个数字 % 作为参数,并把给定的函数调用 % 次。5.10 Infinite recursion 5.10 无限递归
If a recursion never reaches a base case, it goes on making recursive calls forever, and the program never terminates. This is known as infinite recursion, and it is generally not a good idea. Here is a minimal program with an infinite recursion:
%00000205
In most programming environments, a program with infinite recursion does not really run forever. Python reports an error message when the maximum recursion depth is reached:
%00000206
This traceback is a little bigger than the one we saw in the previous chapter. When the error occurs, there are 1000 %000002 frames on the stack!
%000002 栈帧!5.11 Keyboard input 5.11 键盘输入
The programs we have written so far are a bit rude in the sense that they accept no input from the user. They just do the same thing every time.
Python 2 provides a built-in function called %00000209 that gets input from the keyboard. In Python 3, it is called %0000. When this function is called, the program stops and waits for the user to type something. When the user presses Return or Enter, the program resumes and %00000211 returns what the user typed as a string.
%00000212 的内置函数,用来从键盘获取输入。在 Python 3 中,它叫 %0000。调用这个函数时,程序会停下来等待用户输入。当用户按下回车或 Enter 键,程序继续运行,%00000214 会返回用户所输入的内容,类型为字符串。%00000215
Before getting input from the user, it is a good idea to print a prompt telling the user what to input. %00000216 can take a prompt as an argument:
%00000217 可以接受一个提示作为实参:%00000218
The sequence %0 at the end of the prompt represents a newline, which is a special character that causes a line break. That’s why the user’s input appears below the prompt.
%0 表示一个换行符(newline),它是一种特殊字符,会引起换行。所以用户的输入会出现在提示的下一行。If you expect the user to type an integer, you can try to convert the return value to %00:
%00:%00000223
But if the user types something other than a string of digits, you get an error:
%00000224
We will see how to handle this kind of error later.
5.12 Debugging 5.12 调试
The traceback Python displays when an error occurs contains a lot of information, but it can be overwhelming, especially when there are many frames on the stack. The most useful parts are usually:
- What kind of error it was, and
- Where it occurred.
- 错误是什么类型,以及
- 它发生在哪里。
Syntax errors are usually easy to find, but there are a few gotchas. Whitespace errors can be tricky because spaces and tabs are invisible and we are used to ignoring them.
%00000225
In this example, the problem is that the second line is indented by one space. But the error message points to %, which is misleading. In general, error messages indicate where the problem was discovered, but the actual error might be earlier in the code, sometimes on a previous line.
%,这会产生误导。一般来说,错误信息指示的是问题被发现的位置,而真正的错误可能出现在更早的代码里,有时在前一行。The same is true of runtime errors.
Suppose you are trying to compute a signal-to-noise ratio in decibels. The formula is SNRdb = 10 log10 (Psignal / Pnoise). In Python, you might write something like this:
%00000228
But when you run it in Python 2, you get an error message.
%00000229
The error message indicates line 5, but there is nothing wrong with that line. To find the real error, it might be useful to print the value of %0000, which turns out to be 0. The problem is in line 4, because dividing two integers does floor division. The solution is to represent signal power and noise power with floating-point values.
%0000 的值也许有帮助,结果它等于 0。问题出在第 4 行,因为两个整数相除执行的是整除(floor division)。解决办法是用浮点数值来表示信号功率和噪声功率。In general, error messages tell you where the problem was discovered, but that is often not where it was caused.
In Python 3, this example does not cause an error; the division operator performs floating-point division even with integer operands.
5.13 Glossary 5.13 术语表
- modulus operator:
- An operator, denoted with a percent sign (
%), that works on integers and yields the remainder when one number is divided by another. - boolean expression:
- An expression whose value is either
%000 or%0000. - relational operator:
- One of the operators that compares its operands:
%0,%0,%000,%000,%0000, and%0000. - logical operator:
- One of the operators that combines boolean expressions:
%00,%0, and%00. - conditional statement:
- A statement that controls the flow of execution depending on some condition.
- condition:
- The boolean expression in a conditional statement that determines which branch is executed.
- compound statement:
- A statement that consists of a header and a body. The header ends with a colon (:). The body is indented relative to the header.
- branch:
- One of the alternative sequences of statements in a conditional statement.
- chained conditional:
- A conditional statement with a series of alternative branches.
- nested conditional:
- A conditional statement that appears in one of the branches of another conditional statement.
- recursion:
- The process of calling the function that is currently executing.
- base case:
- A conditional branch in a recursive function that does not make a recursive call.
- infinite recursion:
- A recursion that doesn’t have a base case, or never reaches it. Eventually, an infinite recursion causes a runtime error.
- modulus operator 取模运算符:
- 一种用百分号(
%)表示的运算符,作用于整数,返回一个数除以另一个数时的余数。 - boolean expression 布尔表达式:
- 值要么为
%000、要么为%0000 的表达式。 - relational operator 关系运算符:
- 用来比较操作数的运算符之一:
%0、%0、%000、%000、%0000 和%0000。 - logical operator 逻辑运算符:
- 用来组合布尔表达式的运算符之一:
%00、%0 和%00。 - conditional statement 条件语句:
- 依据某个条件来控制执行流的语句。
- condition 条件:
- 条件语句中决定执行哪个分支的布尔表达式。
- compound statement 复合语句:
- 由头部和主体构成的语句。头部以冒号(:)结尾。主体相对头部缩进。
- branch 分支:
- 条件语句中若干备选语句序列之一。
- chained conditional 链式条件:
- 带有一系列备选分支的条件语句。
- nested conditional 嵌套条件:
- 出现在另一个条件语句的某个分支中的条件语句。
- recursion 递归:
- 调用当前正在执行的函数这一过程。
- base case 基础情形:
- 递归函数中不再进行递归调用的条件分支。
- infinite recursion 无限递归:
- 没有基础情形、或永远到达不了基础情形的递归。最终,无限递归会引发运行时错误。
5.14 Exercises 5.14 习题
Exercise 3 Fermat’s Last Theorem says that there are no positive integers a, b, and c such that
an + bn = cn
for any values of n greater than 2.
- Write a function named
%00000256 that takes four parameters—%,%,%and%—and that checks to see if Fermat’s theorem holds. If n is greater than 2 and it turns out to be true that an + bn = cn, the program should print, "Holy smokes, Fermat was wrong!" Otherwise the program should print, "No, that doesn’t work." - Write a function that prompts the user to input values for
%,%,%and%, converts them to integers, and uses%00000265 to check whether they violate Fermat’s theorem.
- 写一个名为
%00000266 的函数,它接受四个参数——%、%、%和%——并检查费马定理是否成立。如果 n 大于 2 且确实有 an + bn = cn,程序应当打印「Holy smokes,费马错了!」;否则程序应当打印「No,那不成立。」 - 写一个函数,提示用户输入
%、%、%和%的值,把它们转换成整数,并用%00000275 检查它们是否违背了费马定理。
Exercise 4 If you are given three sticks, you may or may not be able to arrange them in a triangle. For example, if one of the sticks is 12 inches long and the other two are one inch long, it is clear that you will not be able to get the short sticks to meet in the middle. For any three lengths, there is a simple test to see if it is possible to form a triangle:
If any of the three lengths is greater than the sum of the other two, then you cannot form a triangle. Otherwise, you can. (If the sum of two lengths equals the third, they form what is called a "degenerate" triangle.)
如果三段长度中有任意一段大于另外两段之和,就无法构成三角形;否则可以。(如果两段长度之和等于第三段,它们构成所谓「退化」三角形。)
- Write a function named
%00000276 that takes three integers as arguments, and that prints either "Yes" or "No," depending on whether you can or cannot form a triangle from sticks with the given lengths. - Write a function that prompts the user to input three stick lengths, converts them to integers, and uses
%00000277 to check whether sticks with the given lengths can form a triangle.
- 写一个名为
%00000278 的函数,它接受三个整数作为参数,并根据给定长度的木棍能否构成三角形来打印「Yes」或「No」。 - 写一个函数,提示用户输入三根木棍的长度,把它们转换成整数,并用
%00000279 检查给定长度的木棍能否构成三角形。
The following exercises use TurtleWorld from Chapter 4:
Exercise 5 Read the following function and see if you can figure out what it does. Then run it (see the examples in Chapter 4).
%00000280
Figure 5.2: A Koch curve.
Exercise 6 The Koch curve is a fractal that looks something like Figure 5.2. To draw a Koch curve with length x, all you have to do is
- Draw a Koch curve with length x/3.
- Turn left 60 degrees.
- Draw a Koch curve with length x/3.
- Turn right 120 degrees.
- Draw a Koch curve with length x/3.
- Turn left 60 degrees.
- Draw a Koch curve with length x/3.
- 画一条长度为 x/3 的科赫曲线。
- 左转 60 度。
- 画一条长度为 x/3 的科赫曲线。
- 右转 120 度。
- 画一条长度为 x/3 的科赫曲线。
- 左转 60 度。
- 画一条长度为 x/3 的科赫曲线。
The exception is if x is less than 3: in that case, you can just draw a straight line with length x.
- Write a function called
%000 that takes a turtle and a length as parameters, and that uses the turtle to draw a Koch curve with the given length. - Write a function called
%00000282 that draws three Koch curves to make the outline of a snowflake. Solution:%00000283 . - The Koch curve can be generalized in several ways. See
%00000284 for examples and implement your favorite.
- 写一个名为
%000 的函数,它接受一只乌龟和一个长度作为参数,并用这只乌龟画出给定长度的科赫曲线。 - 写一个名为
%00000286 的函数,画出三条科赫曲线,构成雪花的轮廓。 参考解答:%00000287 。 - 科赫曲线有几种推广方式。参见
%00000288 中的例子,并实现你最喜欢的一种。