= 0
thesum for i in [3,2,1,9.9]:
+= i thesum
7 Loops
Loops allow programs to rerun the same block of code multiple times. This might seem like a funny thing to want to do but it turns out that there are many important tasks that are repetitive in nature (perhaps with small changes for each successive repetition). A loop provides a succinct and efficient way to perform tasks of this nature.
7.1 for
loops
The for
loop is probably the most common loop you will encounter and is a good choice when you know beforehand exactly what things you want to loop over. Here is an example of a for
loop that is used to add up the elements of a list.
This would be equivalent to the following code:
= 0
thesum
= thesum + 3
thesum = thesum + 2
thesum = thesum + 1
thesum = thesum + 9.9 thesum
which isn’t that much longer than using a loop. However, as the list gets longer and/or the mathematical operations being performed get more complex the second method would get unreasonably long.
The correct language is to say that we are iterating over the list [3,2,1,9.9]
. This means that the loop variable (i
in this case but you can choose it to be whatever you want) gets assigned the values of the list elements, one by one, until it reaches the end of the list. You can use for
loops to iterate over any multi-element object like lists or tuples. Python uses indentation to indicate where the loop ends. In this case there was only one statement inside to loop, but if you wanted more than one each line should be indented.
To Do:
- Add a
thesum
.- Predict what the output will be and then run the code and verify that you were correct.
- Now change the loop variable to be named
physics
and verify that the loop still works as expected.
You can iterate over range
objects and strings using for
loops.
for i in ['Physics', 'is','so','fun']: # Iterate over a list of strings
print(i)
Physics
is
so
fun
for i in range(5,50,3): #Generates a list from 5 -> 50 with a step size of 3
print(i)
5
8
11
14
17
20
23
26
29
32
35
38
41
44
47
These examples are so simple that you might wonder when a loop might actually be useful to you. Let’s see if we can build a loop to calculate the following sum
\[ \sum_{n=1}^{1000} {1\over n^2} \tag{7.1}\]
= 0
theSum for n in range(1,1000):
= theSum + 1/n**2
theSum print(theSum)
1.6439335666815615
Here, n
is being assigned the values 1,2,3,4....1000
, one by one, until it gets all the way to 1000. Each time through the loop, n
is different and the expression 1/n**2
evaluates to a new value. The variable theSum
is updated each time through to be the running total of all calculations performed thus far. Here’s another example of a loop used to calculate the value of \(20!\):
= 1
theProduct for n in range(1,21):
= theProduct * n #Multiply theProduct by n
theProduct print(theProduct)
2432902008176640000
Remember that the range function creates a list starting at \(1\), going up to \(21\) but not including it. The math library has a function called factorial
that does the same thing. Let’s use it to check our answer:
from math import factorial
20) factorial(
2432902008176640000
7.1.1 Boolean Logic Inside Loops
Often when using loops, we only want a block of code to execute when some condition is satisfied. We can use boolean logic inside of the loop to accomplish this. For example, let’s write a loop to compute the following sum:
\[ \sum_{{n\over 5} \in \text{ Int and } {n\over 3} \in \text{ Int}} {1\over n^2} \]
which is similar to the one we did above, but this time we only want to include terms where \(n\) is a perfect multiple of both 5 and 3. To check to see if n
is a perfect multiple of a number we can calculate the modulo (remainder after division) using the %
operator and check that it is equal to zero.
= 0
theSum for n in range(1,1000):
if n % 5 == 0 and n % 3 == 0:
= theSum + 1/n**2
theSum print(theSum)
0.007243985583159138
To Do:
Perform the following modifications to the loop above.
- Increase the upper bound of the sum to go up to and include \(5000\).
- Only include the terms where
n
is a multiple of 5 and 3 or is a multiple of 7.- Replace the statement that updates
theSum
to its shorthand version.
7.1.2 Zipping and Enumerating
There are times when it is necessary to iterate over two lists simultaneously. For example, let us say that we have a list of atomic numbers (AN
) and a list of approximate atomic masses (mass
) of the most abundant isotopes for the first six elements on the periodic table.
AN = [1,2,3,4,5,6]
mass = [1,4,7,9,11,12]
If we want to calculate the number of neutrons in each isotope, we need to subtract each atomic number from the atomic mass. To accomplish this, it would be nice to iterate over both lists simultaneously
7.1.2.1 Zipping
The simplest way to iterate over two lists simultaneously is to combine both lists into a single, iterable object and iterate over it once. The zip
function does just that by merging two lists or tuples into a nested list
= [1,2,3,4,5,6]
AN = [1,4,7,9,11,12]
mass
= zip(AN,mass)
zipped
for pair in zipped:
print(pair[1] - pair[0])
0
2
4
5
6
6
The zip objects are “single use” so you can’t reuse zipped
in a later loop. If the two lists being zipped are not the same length, zip
stops zipping when it reaches the end of the shorter list.
To Do:
- Print the variable
zipped
and inspect closely. Was the output what you expected?
- Now do
print(tuple(zipped))
and inspect closely. Draw a conclusion.- Add a few more entries to the list named
AN
, but don’t add the corresponding entries to the other list. Now the lists being zipped aren’t the same length. Inspect the output of the print statement to determine whatzip
does in this scenario.
7.1.2.2 Enumeration
A close relative to zip
is enumerate
which zips a list to the index value for that list (read that last statement again). It also returns a “single use” object that can be iterated over.
= [1,2,3,4,5,6]
AN = [1,4,7,9,11,12]
mass
= enumerate(mass)
enum
for idx,val in enum:
print(val - AN[idx])
0
2
4
5
6
6
To Do:
- Repeat the previous To-Dos for the cell above.
7.1.3 List Comprehension
It is fairly common to use a for
loop to populate a list with a sequence of numbers.
= []
myList
for i in range(10):
**2)
myList.append(i
print(myList)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
This entire process can be compressed down into a single line by expressing the for
loop in square brackets. This is known as list comprehension. The code below will generate the list as above.
= [i**2 for i in range(10)]
myList print(myList)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
List comprehension can take a little time to get used to but it is well worth it. It saves both time and space and makes code less cluttered. You can even add boolean expressions to your conditionals for further control of the final result.
= [i**2 for i in range(10) if i %2 == 0] # Include only the evens.
myList print(myList)
[0, 4, 16, 36, 64]
To Do:
Think of your favorite mathematical function and modify the code above to generate a few samples from it.
7.2 while
Loops
Logic can be combined with loops using something called a while
loop. A while
loop is a good choice when you don’t know beforehand exactly how many iterations of the loop will be executed but rather want the loop to continue to execute until some condition is met. As an example, notice that in Equation 7.1, the terms in the sum get progressively smaller as \(n\) gets bigger. It doesn’t make sense to continue adding to the sum once the terms get very small. Let’s compute this sum by looping until the fraction \({1 \over n^2}\) become smaller than \(1 \times 10^{-2}\).
= 1 # Load the first term in the sum
term = term # Initialize the sum
s = 1 # Set a counter
n while term > 1e-2: # Loop while term is bigger than 1e-2
= n + 1 #Add 1 to n so that it will count: 2,3,4,5
n = 1./n**2 # Calculate the next term to add
term = s + term # Add 1/n^2 to the running total s
This loop will continue to execute until term<1e-2
. Note that unlike the for
loop, here you have to do your own counting if you need to know how many iterations have been performed. Be careful about what value n
starts at and when it is incremented (n = n + 1
). Also notice that term
must be assigned prior to the start of the loop. If it wasn’t the loop’s first logical test would fail and the loop wouldn’t execute at all.
To Do:
- Decrease the threshold on the termination condition and observe any changes in the final result and how many more iterations are performed.
- After toying around with it for a while pick a termination condition that you feel will produce a result that is accurate.
while
loops should be used with caution because you can easily write a faulty termination condition and inadvertently write a loop that runs forever. This happens because your termination condition was never met. An example of this is given below.
Warning: Do not execute the code block below!!
= 0
x
while x != 10:
= x + 3
x print("Done")
The loop above is intended to end after a few iterations when the value of x is equal to 10. However, closer inspection reveals that the value of x will never be equal to 10. After the first iteration x is equal to 3, then 6,9,12,15 and so on… but never 10. This loop will run forever because the termination condition is never met (x != 10
never produces a False
)!! If you choose to use a while
loop, triple check your termination condition to make sure you haven’t made a mental error. Avoiding the use of !=
or ==
in your termination condition will help too. Use <=
or >=
instead.
To Do:
- Modify the termination condition in the loop above so that it terminates when
x
gets larger than 15.- Run the code and verify that you did it correct.
7.3 continue
, break
, and pass
Commands
The continue
, break
, and pass
commands are used to control the flow of code execution in loops. Here is a description of their usage:
Operator | Description |
---|---|
break |
Exits a for /while loop. |
continue |
Skips the remaining loop block and begins the next iteration. |
pass |
No action; code contiues on |
The break
statement is useful when you want to completely stop a loop early. Here is our sum loop rewritten with a break
statement added to stop the loop after 1000 iterations.
= 1 # Load the first term in the sum
term = term # Initialize the sum
s = 1 # Set a counter
n while term > 1e-10: # Loop while term is bigger than 1e-10
+= 1 #Add 1 to n so that it will count: 2,3,4,5
n = 1./n**2 # Calculate the next term to add
term += term # Add 1/n^2 to the running total
s if n > 1000:
print('This is taking too long. I''m outta here...')
break
This is taking too long. Im outta here...
The continue
statement is similar to break
except that instead of stopping the loop, it only stops the current iteration of the loop. All code below the continue
statement will be skipped and the next iteration will begin. For example, if you wanted to do the sum from equation ?? but only include those terms for which n is a multiple of 3, it could be done like this:
= 1 # Load the first term in the sum
term = term # Initialize the sum
s = 1 # Set a counter
n while term > 1e-10: # Loop while term is bigger than 1e-10
+= 1 #Add 1 to n so that it will count: 2,3,4,5
n if n % 3 != 0:
continue
= 1./n**2 # Calculate the next term to add
term += term # Add 1/n^2 to the running total s
Now, when the value of n
is not a multiple of 3, the sum will not be updated and the associated terms are effectively skipped.
Finally, the pass
statement does nothing. Seriously!! It is merely a place holder for code that has not bee written yet. Usually, you’ll use the pass
statement to run and test code without errors due to missing code.