While loops

A for loop runs once per item. A while loop runs as long as a condition is true, which is what you need when you do not know in advance how many times to go round.

stock = 2
while stock < 10:
    stock += 3
    print("Restocked to", stock)
print("Done")

Before each round Python checks stock < 10. If true, the block runs; if false, the loop ends and the program continues after it. Here it runs three times: 5, 8, 11.

Counting with while

Anything for with range can do, while can do with a counter, though for is shorter when the count is known.

i = 0
while i < 3:
    print("Box", i)
    i += 1

The i += 1 is essential. Without it the condition never changes.

The infinite loop

Delete the i += 1 line above and run it. The condition i < 3 stays true forever, so the loop never ends. The output box fills with "Box 0", and this site stops the program after ten seconds. A real program would run until you killed it.

Press Stop if you get tired of waiting. Every while loop needs something in its body that eventually makes the condition false. When a program hangs, that missing line is the first thing to look for.

Leaving early with break

break ends the loop immediately, whatever the condition says. It is the usual way to write "loop until something is found":

prices = [40, 25, 60, 2.5]
i = 0
while i < len(prices):
    if prices[i] > 50:
        print("First expensive item is at position", i)
        break
    i += 1

break works in for loops too. Inside a function there is a second way out: return ends the whole function at once, loop included, which is often the neatest way to write "return the first one that matches".

Which loop?

Use for when you are going through items or a known number of times. Use while when the number of rounds depends on what happens inside the loop: halving until small enough, retrying until it works, reading until the end.

Try it

Restock until full

Deliveries arrive in boxes of box loaves. Write deliveries_needed(stock, box, target) that returns how many boxes must be added before stock reaches at least target. If stock already meets the target, return 0.

deliveries_needed(2, 3, 10)   ->  3     (2 -> 5 -> 8 -> 11)
deliveries_needed(10, 3, 10)  ->  0
def deliveries_needed(stock, box, target):
    boxes = 0
    while ...:
        ...
    return boxes

Halve until under

A price is cut in half repeatedly until it is below limit. Write halvings(price, limit) that returns how many halvings that takes. If the price is already below the limit, return 0.

halvings(100, 10)  ->  4     (100 -> 50 -> 25 -> 12.5 -> 6.25)
halvings(5, 10)    ->  0
def halvings(price, limit):
    ...

First item over a price

Write first_over(prices, limit) that returns the position of the first value in prices that is greater than limit, or -1 if there is none.

first_over([40, 25, 60, 2.5], 50)  ->  2
first_over([40, 25], 50)           ->  -1
def first_over(prices, limit):
    i = 0
    while i < len(prices):
        ...
        i += 1
    return -1

Next: Dictionaries.