3.7. Loops¶
Loops are useful programming concepts that you will find in just about every lanugage because they allow us to repeat a set of instructions many times. We discuss in the style section how loops can help do repetitions for us, so we don’t need to repeat code.
Python has two types of loops, the for loop and the while loop. Any repeated task can be done with either kind of loop, but as we’ll see, you might prefer to choose one type over the other in certain scenarios.
3.7.1. Indentation¶
In Python, blocks of code are denoted by their indentation level. A loop will repeat only the lines which are indented, then stop once the indentation returns to normal. In the following example, the two indented lines are repeated, but the final line only runs once because it is outside the loop (back to normal indentation).
for i in (1, 2, 3):
result = i**2
print(result)
print("Finished!")
3.7.2. For loop¶
A for loop is most often used to iterate through a collection of objects like a list
, tuple
, or string
. At each iteration, we get access to the next element in the collection and can do some work on that element.
squares = [1, 4, 9, 16, 25]
for square in squares:
print(square)
print("We printed", len(squares), "squares")
In the above example, the squares
list is the collection we are looping through, and square
is a variable that Python re-defines every iteration to be the next element in squares
.
Iteration by iteration, we get:
On the first iteration,
square == 1
On the second iteration,
square == 4
On the third iteration,
square == 9
On the fourth iteration,
square == 16
On the fifth iteration,
square == 25
After
25
, there are no more elements insquares
, so the loop ends and Python runs the next unindented line (the finalprint()
statement)
We can choose any variable name that we’d like when define the for loop, it didn’t have to be square
.
squares = [1, 4, 9, 16, 25]
for x in squares:
print(x)
print("We printed", len(squares), "squares")
squares = [1, 4, 9, 16, 25]
for jack_russell_terrier in squares:
print(jack_russell_terrier)
print("We printed", len(squares), "squares")
Aside: Good naming conventions
As we have said before in this text and will say again:
good naming conventions will save you a lot of future headaches
It is good style to name our variables something expressive that reveals what they are. For example, in the squares
list above, each element is a square number, making square
a more logical choice for our loop variable than jack_russell_terrier
(regardless of how much cuter our code is with dogs).
Readability
When we use good naming conventions in Python, something magical happens: most of the code you write will read like plain English (with a couple words inferred here and there).
For example, if we wanted to describe what the loop above did, we could say:
Go through the list of squares one element at a time, and for each square in the list, print the square
In Python code (with expressive names for our list and loop variable), we can translate it to Engligh by adding very few extra words:
for square in squares: # for [each] square in [the] squares [list],
print(square) # print [the] square
3.7.3. Range¶
A useful built-in function that we commonly use in for loops is range()
. Range is a quick way to make sequence of numbers to loop through.
r = range(5)
print(type(r))
print(r)
It seems like range
is its own type in Python. Let’s see what happens when we loop through a range
object:
for i in range(10): # Loop through numbers 0 to 9
print(i)
If we want to start at another value, we can specify two arguments in range()
, the start
and stop
:
for i in range(37, 42):
print(i)
Note: Like when slicing, the end index is excluded from the range. This way, if you specify a range from (37, 42)
, there are 42-37 = 5
numbers in the range, as printed above.
We can also change the spacing of the elements in our range by specifying a third argument to range()
.
for i in range(0, 15, 3):
print(i)
Often the range()
function is useed to get indices to loop over, and it’s convention to reserve i
, j
, and k
for index variables. When we loop over the indices of a list
, tuple
, or string
, we can then access each item one at a time with that index.
fruits = ['banana', 'apple', 'pear', 'tomato']
for i in range(4):
print("We are on index", i)
print(fruits[i])
We commonly want to loop through all of the elements of a collection of items, like in the code block above. To do this in general (without needing to count up all the elements to pass as a number to range), we can just pass in the len()
of that collection. This allows us to always loop to the end of the collection, even if its length changes.
fruits = ['banana', 'apple', 'pear', 'tomato']
for i in range(len(fruits)):
print(i, ":", fruits[i])
fruits.append('pineapple')
fruits.append('plum')
print("\nOh no! Added more fruit!\n")
for i in range(len(fruits)):
print(i, ":", fruits[i])
3.7.4. Enumerate¶
We will often want to loop a collection of items, but also want to know the indices of those values. To do this, we can do the following which works, but is a little messy:
vegetables = ['carrot', 'lettuce', 'zucchini']
for i in range(len(vegetables)):
print("Index", i, ":", vegetables[i])
Alternatively, we can use the enumerate()
function, which is a shortcut to get the index and value in each iteration of the loop.
Note: enumerate()
completely replaces the ugly range(len())
and allows us to pick a good variable name for our loop variable!
for i, vegetable in enumerate(vegetables):
print("Index", i, ":", vegetable)
3.7.5. Practice for loops¶
Sort the following list of names in alphabetical order (by first name)
Loop through the list and
print the rank of the name in alphabetical order
print the last name of the person at that rank
Hints: the list method, .sort()
, and the string method .split()
may be useful. Also your ranking should start at 1 (not 0)!
cool_scientists = ['Marie Curie', 'Jane Goodall', 'Vera Rubin', 'Mae Jemison',
'Rosalind Franklin', 'Donna Strickland', 'Frances Arnold']
# Write and test your solution here
3.7.6. While loops¶
A while loop is similar to the for loop, except it is defined in terms of a end condition, rather than a collection of elements.
While loops should be used when you need to loop until a condition is met, often in these cases, we do not know how many iterations we will need to complete.
capacity = 100
people = 0
while people < capacity:
people += 10
print("Number of people:", people)
print("We're at capacity!")
Let’s unpack the example above:
Initially,
people
(0) begins less thancapacity
(100), so the while condition isTrue
and we enter the loopEach iteration, we increase
people
by 10After 10 iterations,
people
is greater or equal to capacity, so the while condition is no longerTrue
and we exit the loopFinally we continue running the next line outside the loop (the final
print()
statement)
Although you generally want to use a for loop to iterate over a collection of elements, we can also accomplish the same thing with a while loop, but we have to keep track of our iterator variable manually.
dogs = ['husky', 'poodle', 'greyhound', 'boxer', 'shibe']
i = 0 # we need to define our iterator before the loop
while i < len(dogs):
print(dogs[i])
i = i + 1 # Don't forget to increment the iterator!
print("Much wow! Many dog!")
What do you think happens if we left out the i = i + 1
line? Think about the i < len(dogs)
condition. If you’re brave, run the next code block:
dogs = ['husky', 'poodle', 'greyhound', 'boxer', 'shibe']
i = 0 # we need to define our iterator before the loop
while i < len(dogs):
print(dogs[i])
With while loops, it is very important to make sure that the loop can terminate, that is, that the while condition will become False
at some point. Otherwise we can get sneaky infinite loops in our code.
3.7.7. Practice while loops¶
Say we want to see how many times we can (integer) divide a number by 2 before it is less than or equal to 1. We don’t know how many times we need to divide the number when we start, but we do know when to stop. We should use a while loop!
Write the condition that allows the following code to terminate correctly:
num = 99
count = 0
while False: # replace False with the correct condition
num = num // 2
count += 1
print("The base 2 log of 99 is", count)
Given the following list,
sort the list in alphabetical order (by first name)
using a while loop, print each name that starts with a letter before ‘n’
Hint: try comparing two letters, e.g. a < e
or f < b
cool_scientists = ['Marie Curie', 'Jane Goodall', 'Vera Rubin', 'Mae Jemison',
'Rosalind Franklin', 'Donna Strickland', 'Frances Arnold']
# Write and test your solution here