Iteration
Repetition, Repetition, Repetition, Repe…
For Loops
We’ve seen simple iteration over a sequence with for ... in
:
In [170]: for x in "a string":
.....: print(x)
.....:
a
s
t
r
i
n
g
No Indexing Required
Contrast this with other languages, where you must build and use an index
to iterate through an array.
for(var i = 0; i < arr.length; i++) {
var value = arr[i];
alert(i + ") " + value);
If you do need an index, you can use enumerate
:
In [140]: for idx, letter in enumerate('Python'):
.....: print(idx, letter, end=' ')
.....:
0 P 1 y 2 t 3 h 4 o 5 n
range
and for
Loops
The range
builtin is useful for looping a known number of times:
In [171]: for i in range(5):
.....: print(i)
.....:
0
1
2
3
4
But you don’t really need to do anything at all with i
In fact, it’s a common convention to make this clear with a “nothing” name:
In [21]: for __ in range(5):
....: print("*")
....:
*
*
*
*
*
No Namespace
Be alert that a loop does not create a local namespace:
In [172]: x = 10
In [173]: for x in range(3):
.....: pass
.....:
In [174]: x
Out[174]: 2
Loop Control
Sometimes you want to interrupt or alter the flow of control through a loop.
Loops can be controlled in two ways, with break
and continue
.
The break
keyword will cause a loop to immediately terminate:
In [141]: for i in range(101):
.....: print(i)
.....: if i > 50:
.....: break
.....:
0 1 2 3 4 5... 46 47 48 49 50 51
The continue
keyword will skip later statements in the loop block, but
allow iteration to continue:
In [143]: for in in range(101):
.....: if i > 50:
.....: break
.....: if i < 25:
.....: continue
.....: print(i, end=' ')
.....:
25 26 27 28 29 ... 41 42 43 44 45 46 47 48 49 50
Take some time to look at these examples carefully, and make sure you understand them. It’s probably a good idea to write a bit of code to experiment as well.
else
For loops can also take an optional else
block.
This is not a feature of most languages, but it can be handy.
Executed only when the loop exits normally (not via break):
In [147]: for x in range(10):
.....: if x == 11:
.....: break
.....: else:
.....: print('finished')
finished
In [148]: for x in range(10):
.....: if x == 5:
.....: print(x)
.....: break
.....: else:
.....: print('finished')
5
This is a really nice, unique Python feature!
If Python didn’t have else
on loops, you’d need to set a flag, something like:
it_did_break = False
for x in range(10):
if x == 11:
it_did_break = True
break
if not it_did_break:
print('finished')
That’s klunkier, no?
Make sure to try this a bit yourself too, to make sure you get it.
While Loops
While loops are different – they are not for iterating over a collection, but rather for repeating something an unknown number of times – and maybe even forever – or until the program terminates.
The while
keyword is for when you don’t know how many loops you need.
It continues to execute the body until the associated condition does not evaluate to True:
while a_condition:
some_code
in_the_body
while
vs. for
while
is more general than for
– you can always express for
as while
, but not always vice-versa.
while
is more error-prone – requires some care to terminate.
The loop body must make progress, so the associated condition can become False
.
Care must be taken to avoid an unintended error – infinite loops:
i = 0;
while i < 5:
print(i)
Terminating a while Loop
Use break
:
In [150]: while True:
.....: i += 1
.....: if i > 10:
.....: break
.....: print(i)
.....:
1 2 3 4 5 6 7 8 9 10
Set a flag:
In [156]: import random
In [157]: keep_going = True
In [158]: while keep_going:
.....: num = random.choice(range(5))
.....: print(num)
.....: if num == 3:
.....: keep_going = False
.....:
3
Use a condition:
In [161]: while i < 10:
.....: i += random.choice(range(4))
.....: print(i)
.....:
0 0 2 3 4 6 8 8 8 9 12
Similarities
Both for
and while
loops can use break
and continue
for
internal flow control.
Both for
and while
loops can have an optional else
block.
In both loops, the statements in the else
block are only executed if the
loop terminates normally (no break
).
Pythonic Iteration
I’ve already said it, but it bears repeating:
for loops are for iterating over something (an “iterable”) – you almost never want to iterate over the indexes, and then access items with the index.
Nifty for loop tricks
tuple unpacking:
remember this?
x, y = 3, 4
You can do that in a for loop, also:
In [4]: l = [(1, 2), (3, 4), (5, 6)]
In [5]: for i, j in l:
print("i:{}, j:{}".format(i, j))
i:1, j:2
i:3, j:4
i:5, j:6
Looping through two iterables at once:
zip
In [10]: l1 = [1, 2, 3]
In [11]: l2 = [3, 4, 5]
In [12]: for i, j in zip(l1, l2):
print("i:{}, j:{}".format(i, j))
i:1, j:3
i:2, j:4
i:3, j:5
There can be more than two:
for i, j, k, l in zip(l1, l2, l3, l4):
Need the index and the item?
enumerate
In [2]: l = ['this', 'that', 'the other']
In [3]: for i, item in enumerate(l):
...: print("the {:d}th item is: {:s}".format(i, item))
...:
the 0th item is: this
the 1th item is: that
the 2th item is: the other