Loops

We’re all familiar with loops – a perfect loop, of course, is the tell-tale sign of a great GIF. For example, the famous “Bro, do you even loop?” is one we’ve all seen.

Loops in coding are quite similar. In these loops, however, we want to do something slightly different every time rather than the exact same thing like in a GIF.

So why do we use loops? Because we’re lazy! Computer scientists are lazy people, and the lazier the better. If you can type as little as possible and still come up with a solution, that’s the best case scenario. Imagine we’re making a countdown app.

We could do this.

print "10"
print "9"
print "8"
print "7"
print "6"
print "5"
print "4"
print "3"
print "2"
print "1"
print "BLASTOFF!"

Wow. What a pain in the Bieber. Even with copy-paste that was incredibly annoying. Surely there must be an easier way to do this! Enter loops. With loops, we can do this in just three lines of code.

While Loops

Remember our primitive types? Yes, I will keep asking you about them because they’re important. Our primitive types are int, float, str, and bool. Every expression has a type. Some expressions, like 5 + 5 are integer expressions.

Last time in class, you learned about a special type of expression that results in a boolean value. Surprisingly, we call these boolean expressions. A simple example is 5 > 3, which evalutes to the boolean value True.

While loops have two parts: a header and a body.

The loop header looks like this

while <your code here> :

That’s it. But what goes inside <your code here>? A boolean expression! Any boolean expression. So what’s an example of a boolean expression? Is True a boolean expression? Of course it is. Remember that even just a plain old vanilla value is also an expression.

The body of the loop looks like plain old python code, just indented one level. So let’s look at our same old count-down example.

i = 1
while i > 0:
    print str(i)
    i = i - 1

The most important thing to remember is that the while loop checks whether the header evalutes to True before it executes the body, not afterwards. So every single iteration, it checks that the header is still True and only then continues.

Let’s manually step through the iteration. First, i starts out at 1. Obviously, 1 > 0 is True. Great, so the loop goes on to the body and prints i as a string. Then, it subtracts 1 from i.

Then it goes back up to the header. It asks whether 0 > 0 is True. Nope! It’s not. So it goes to the end of the program, skipping the body of the loop, and completes.

So let’s do some quizzes. I’ll give you code, and you tell me the output.

i = 5
while i > 3:
    j = i
    i = 0
    print str(i)
    i = j - 1

What’s the output?

0
0

Even though the statement i = 0 makes the loop header evaluate to False, the trick here is that the loop only checks whether the header is True before it executes the body. Once that’s true, it executes the entire body even if some lines of the body make the header False.

Cool, what about this one?

while False:
    print "And the winner for the Oscar is Leonardo DiCaprio!"

There’s no output! Remember, even a literal is an expression. This particular literal always evaluates to False, so the loop never executes. If you have code that never executes no matter what, that section of code is called dead code. It’s a very bad thing to have and is often a tell-tale sign of larger problems in the code.

What about the opposite?

while True:
    print " Brad Pitt: 'Oh my gosh, we should adopt a child.' "

This expression always evalutes to True, so the loop never stops executing! This is called an infinite loop, and it means your code will never finish. Uh oh!

So here is Blastoff once again, but with a while loop.

i = 10
while i > 0:
    print str(i)
    i = i - 1   # Could also do i -= 1
print "BLASTOFF!"

For Loops

There’s another type of loop called a for loop. A for loop primarily iterates over lists, so if you’re unfamiliar with lists, I’d recommend reading our section on lists before reading through this.

Much like a while loop, a for loop also has a header and a body. The body of the loop, like any loop, is just regular Python code indented further. The header for for loops, on the other hand, have a slightly different pattern from the while loop headers.

for <variable name> in <some iterable object>:
    # Regular old loop body
    pass

So far, we’ve only seen lists, but there are actually other data structures that we for loops can iterate over. If you’re confused, for now you can imagine for loops as having this formula instead:

for <variable name> in <name of some list>:
    # Regular old loop body
    pass

The trick here, is that <variable name>’s scope is limited to the for loop alone. In other words, the following won’t work.

for a in [1, 2, 3, 4]:
    print a
print a

That second print a won’t work, because a only exists within that for loop.

One point of confusion is when to use range. The problem with for loops is that they must take a list after the in. So if you want to do something 6 times, but there is no list, we have to _create_one. That’s exactly what range does. It’s an easy way to create a list when there isn’t one.

So if we already have a list defined, like a = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1], then our code just has to be this.

for i in a:
    print str(i)
print "BLASTOFF!"

But if we don’t have that list, we have to use

for i in range(10):
    print str(i)
print "BLASTOFF!"

Uh oh… But that’s not right. That counts upwards! So how do we fix that?

Turns out, the function range can behave differently depending on the number of parameters it takes. If it takes one parameter, it counts up from 0 to the number given. If it is given three parameters, the first is the start, the second is the end, and the third is the increment. Here, we want to countdown from 10 to 1, with an increment of -1. So why do we put 0?

Remember that for range, the last number is never included. So range(3) produces [0, 1, 2]. Similarly, range(10, 0, -1) produces [10, 9, 8, 7, 6, 5, 4, 3 ,2, 1].

So here is our countdown example revisited with just three lines of code.

for i in range(10, 0, -1):
    print str(i)
print "BLASTOFF!"

But sometimes we see range even when there is a list already defined! What gives? I’ll give you a hint – it has to do with the variable in the loop header only existing within the loop.

Let’s see if this code works.

someList = [1, 2, 3, 4]
for item in someList:
    item = 0
print someList

So this code will output [0, 0, 0, 0], right? Unfortunately, no. Not only is item’s scope limited to the for loop, it’s actually just a copy of the element within the actual list! It’s not the actual list element. So changing item does not change the list.

So how do we change the actual list? We use range.

someList = [1, 2, 3, 4]
for i in range(len(someList)):
    someList[i] = 0
print someList

Now the code will output [0, 0, 0, 0]. The only way to change the actual elements within a list is by indexing into the list. So the two uses for range is when you don’t have a list to iterate over with a for loop or you want to actually change the list through which you’re iterating.

In general, this results in three types of for loop headers.

The first type where the list is already defined.

for <variable name> in <list name>:
    # do stuff
    pass

The second type where there is no list, so we have to create one with range.

for <variable name> in range(<number>):
    # do stuff
    pass

And the last type where there is a list, but you want to change the values inside of that list.

for <variable name> in range(len(<name of list>)):
    # do stuff like changing values inside the list
    # <name of list>[<variable name>] = some new value
    pass

Pretty neat!

The Clash of Loops

So which type of loop is better?

Obviously, the answer is neither. Otherwise Python would have just gotten rid of the “worse” kind. The truth is different types of loops are suited for different problems. Here are circumstances where for loops excell.

In pretty much every other case, while loops are better. Pretty simple!

Can every program with a for loop be re-written using a while loop? What about vice versa?

The answer to both is yes. They are equivalent. It really is just a matter of convenience. You can use a while loop to go over lists, but for loops are just so much easier so why bother.