For-loops are an important control-flow construct -- they allow you to repeatedly perform batches of similar operations. A for-loops needs an iterable to loop over; lists and their cousins are the most common iterables for this purpose.
# sum the integers from 0 to 5
j = 0
for i in [0, 1, 2, 3, 4, 5]:
j += i
print(i,j)
# ---
0 0 1 1 2 3 3 6 4 10 5 15
A few points about this example.
in
keyword is used to specify the iterable over which we are looping.:
begins the body of the loop.# sum the integers from 0 to 5
j = 0
for i in [0, 1, 2, 3, 4, 5]:
j += i
print(i,j)
# ---
File "<ipython-input-2-eb9b9699de47>", line 4 j += i ^ IndentationError: expected an indented block
The case of looping over integers up to n
is so common that there is a dedicated function for achieving exactly this behavior: the range()
function. To count from 0
to n
inclusive, loop over range(n+1)
:
for i in range(6):
print(i)
# ---
0 1 2 3 4 5
Strings are also iterables:
for l in "to boldly go":
print(l)
# ---
t o b o l d l y g o
A verbose way to achieve the same result, which is sometimes useful:
s = "to boldly go"
for i in range(len(s)):
print(s[i])
# ---
t o b o l d l y g o
We can also use str.split()
to loop over entire words:
for w in "to boldly go".split():
print(w)
# ---
to boldly go
In each case, the indexing variable is assigned in global scope (i.e. outside the context of the for loop), and can be used later if desired.
i, l, w
(11, 'o', 'go')
The indexing variable is reassigned with each iteration of the loop. This can occasionally be a source of mistakes. For example, take a moment to consider the following code: what is the value of i
at the end of the loop?
i = 1
for i in range(10):
i = i*2
i
18
Compare to:
j = 1
for i in range(10):
j = j*2
j
1024
A versatile way to construct lists is by first initiating an empty list, and then incrementally adding to it. Suppose I wanted to make a list of all integer squares up to 100. Here's a way to do this with a for loop:
squares = [] # an empty list
for i in range(1, 11): # i ranges from 1 to 10
squares.append(i**2) # add i**2 to the end of squares
squares
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
We can also create a list of the lengths of words in a string:
s = "to boldly go"
word_lengths = []
for word in s.split():
the_length = len(word)
word_lengths.append(the_length)
word_lengths
[2, 6, 2]
A much more compact and readable way to construct lists is provided by list comprehensions. List comprehensions are inspired by "set-builder" notation in mathematics. For example, we might write the squares
list from above as
List comprehensions allow us to write very similar Python code, using the for
keyword again.
squares = [i**2 for i in range(1, 11)]
squares
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
We were able to condense the three lines of code from our for-loop into just one, readable line. Similarly,
word_lengths = [len(word) for word in s.split()]
word_lengths
[2, 6, 2]
We can also write conditional comprehensions to construct even more complex lists:
even_squares = [i**2 for i in range(1,21) if i % 2 == 0]
even_squares
[4, 16, 36, 64, 100, 144, 196, 256, 324, 400]
We can iterate over multiple indexing variables:
products = [i*j for i in [1,2,3] for j in [4, 5, 6]]
products
[4, 5, 6, 8, 10, 12, 12, 15, 18]
We can also easily construct lists of lists:
products2 = [[i*j for i in [1,2,3]] for j in [4, 5, 6]]
products2
[[4, 8, 12], [5, 10, 15], [6, 12, 18]]
Comprehensions are a powerful tool which should often be preferred to for-loops when constructing lists.