Chapter 7 · pp. 85–92
Iteration
Iteration means running a block of statements again and again. Earlier chapters showed repetition through recursion and through the for loop; this chapter adds the while statement. Along the way it clarifies how assignment works, how to update variables, how to exit a loop early, and how a loop can improve an estimate step by step, as in square roots (p. 85).
Assignment, reassignment and updates
The = sign is not a claim of equality. Many beginners read a = b as "a and b are equal forever," as in a math class. In Python, = is an instruction: take the value on the right and attach the name on the left to it, right now. Two differences show this (pp. 85–86):
- Math equality is symmetric, but assignment is not. The statement a = 7 is legal, while 7 = a is an error, because 7 is not a name that can be given a value.
- A math statement stays true for all time. A Python assignment happens at one moment. After a = 5, then b = a, then a = 3, the variable b is still 5. The two variables matched for a while, but they do not have to stay matched.
Reassignment. Giving a new value to a variable that already exists is called reassignment. The variable stops referring to the old value. If x = 5 is followed by x = 7, then x refers only to 7 (p. 85). Reassignment is very useful, but if values change often, the code becomes harder to read and debug (p. 86).
Updates. An update is a reassignment where the new value depends on the old one. For example, x = x + 1 means: read the current x, add one, and store the result back in x. Python works out the right side first and only then assigns to the left side (p. 86). Adding 1 is called an increment, and subtracting 1 (x = x - 1) is called a decrement (p. 86).
Initialization. Because the right side is evaluated first, the variable must already exist. Running x = x + 1 on a brand-new name gives a NameError, since Python has no value of x to add 1 to. The fix is to initialize first with x = 0. After that, x = x + 1 makes x equal to 1 (p. 86).
The while statement
A while loop repeats its body as long as a condition stays true. The flow of execution has three steps (pp. 86–87):
- Check whether the condition is true or false.
- If it is false, leave the loop and continue with the next statement after it.
- If it is true, run the body, then go back to step 1.
Here is a countdown function:
def countdown(n):
while n > 0:
print(n)
n = n - 1
print('Blastoff!')
For countdown(3), the loop prints 3, then 2, then 1. When n becomes 0, the condition n > 0 is false, the loop ends, and 'Blastoff!' is printed once (p. 87).
Making the loop end. The body should change a variable so that the condition eventually becomes false. If it does not, the loop runs forever, which is an infinite loop (p. 87). In countdown, n drops by 1 on every pass, so it must reach 0. If the line n = n - 1 were deleted, n > 0 would stay true forever. If n starts at zero or below, the body never runs at all (p. 87).
A loop nobody can fully analyze. Some loops are harder to judge. Consider a function that repeats while n != 1. If n is even, it halves n. If n is odd, it sets n to 3n + 1. Starting at 3, the values are 3, 10, 5, 16, 8, 4, 2, 1 (p. 87). For a starting value that is a power of two, such as 16, n stays even all the way down, so the loop clearly stops. But n sometimes goes up and sometimes goes down, and no one has proved that the loop stops for every positive starting value. This open problem is the Collatz conjecture (p. 87).
Leaving a loop with break
Sometimes you only learn it is time to stop in the middle of the body. The break statement jumps out of the loop at once (p. 88). A common pattern is a loop whose condition is simply True:
while True:
line = input('> ')
if line == 'done':
break
print(line)
print('Done!')
The condition is always true, so the loop only ends when break runs. Here, typing done ends it; anything else is echoed back. This style is popular for two reasons. You can test the stop condition anywhere in the body, not just at the top. You can also state it positively ("stop when this happens") instead of negatively ("keep going until that happens") (p. 88).
Newton's method for square roots
Loops are well suited to problems where you start with a rough answer and keep improving it. Newton's method does this for square roots. To find the square root of a, pick almost any estimate x and compute a better one:
y=2x+a/x
Take a = 4 and x = 3. Then y is about 2.1667. Feed that back in as the new x and you get about 2.0064, then 2.00001, then 2.0 (pp. 88–89). The true answer is 2, and each step gets much closer. We usually do not know in advance how many steps are needed, but we know we have arrived when the estimate stops changing (p. 89).
A loop for this computes y, stops if y is close to x, and otherwise sets x = y so the next pass starts from the better estimate (p. 89).
Why not test with ==? It is tempting to stop when y == x. But floats store most numbers, such as 1/3 or the square root of 2, only approximately. Two computed values might never match exactly, and the loop could run much longer than expected or even forever. A safer test uses the absolute value of the difference:
∣y−x∣<ϵ
In Python this is abs(y - x) < epsilon, where epsilon is a small number such as 0.0000001 that defines "close enough" (p. 89).
Check yourself
- After a = 5, b = a, a = 3, what is the value of b, and why does b not change?
- Why does x = x + 1 cause a NameError if x has never been assigned, and how do you fix it?
- In a while loop that counts down, what happens if you forget the line that decreases n?
- How does a while True loop with break differ from a loop whose condition is checked only at the top?
- Why should a loop that uses Newton's method test abs(y - x) < epsilon instead of y == x?