27. Loops#

I just had an heated argument 🔥 with my girlfriend. I need to write 5 times I love you ❤️ as punishment. Let’s start writing 🙁

print("I love you ❤️")
print("I love you ❤️")
print("I love you ❤️")
print("I love you ❤️")
print("I love you ❤️")
I love you ❤️
I love you ❤️
I love you ❤️
I love you ❤️
I love you ❤️

That was pretty easy, it just took me couples of seconds. But what if she asks for 100 times, or 1000 times, I am doomed 😱

Here comes our saviours Loops. Let’s do the same, but using a loop.

count = 0
while count < 5:
    count += 1
    print("I love you ❤️")
I love you ❤️
I love you ❤️
I love you ❤️
I love you ❤️
I love you ❤️

Yup! we did it much easier, how crazy ever my girlfriend is and gives me punishment to write any number of times, I can just change the condition of while loop as count < <number>.

Error

404: My Girlfriend neither found nor exists.😬

Basically loops are used to execute a block of code repeatedly, until a break condition is satisfied. Break condition is not required unless we want to run an infinite loop 🙄.

We have two ways to build loops in Python:

  • while

  • for

To exit the loops explicitly, we can use break keyword. break keyword exits the right loop which it is indented in.

27.1. while#

while loop also works based on the Truth values of the condition/object, if the truth value is True, then the loop continues to execute, else breaks the loop. The syntax of while loop is:

while <condtion>:
    ...

Yipeee! We have already use while loop in our first example. Let’s see more examples.

let’s find even numbers until 20.

number = 0
while number <= 20:
    if number % 2 == 0:
        print(f"{number} is even.")
    number += 1
0 is even.
2 is even.
4 is even.
6 is even.
8 is even.
10 is even.
12 is even.
14 is even.
16 is even.
18 is even.
20 is even.

We dit it 😎! let’s get to the explanation phase:

We have created a integer object number with value 0. We created a while loop with the condition as number <= 20, so until the number is greater than 20, the while loop continues to execute. we have a if condition if number % 2 == 0: that checks if the number is even, if the number is even, then prints saying the number is even, else skips.

number += 1, don’t forget this unless you want to get into infinite loop 😬. For each iteration in while loop, number increments by 1, once the number is incremented to 21, the while loop breaks and doesn’t execute anymore as it is resulting Falsy for the condition number <= 20.

27.2. for#

We have another loop called for, which is used for iterating over the iterator or sequences like list, tuple, str etc..

my_list = ["🐍", "🚀", "😊"]
for obj in my_list:
    print(obj)
🐍
🚀
😊

We can even iterate over strings

for char in "Python":
    print(char)
P
y
t
h
o
n

If we want to iterate over numbers, we can use the range function which generates the values in the given range.

Hint

range function can be called as range(stop) or range(start, stop, step). For range(stop), the iteration starts from 0 until stop(exclusive). For range(start, stop, step), start can be any value and iterates until stop(exclusive) with step given, default step is 1.

for number in range(5, 15, 2):
    print(number)
5
7
9
11
13

27.3. Nested loops#

Just now my lecturer gave me an assignment to find factorial for a few numbers 2, 6, 7, 8, 9, 10. Might be my lecturer doesn’t knew how easily we could use nested-loops to find the factorial of each number given.

First things first, what are nested-loops? The name itself is self explanatory 😎, loop containing a loop is called nested loop. Yup, we got to know about it. let’s start solving the assignment ⚡️.

assignment_numbers = (2, 6, 7, 8, 9, 10)

for number in assignment_numbers:  # First loop.
    factorial = number
    for num in range(1, number):  # Nested Loop.
        factorial *= num
    print(f"Factorial of {number} is {factorial}")
Factorial of 2 is 2
Factorial of 6 is 720
Factorial of 7 is 5040
Factorial of 8 is 40320
Factorial of 9 is 362880
Factorial of 10 is 3628800

Yup! We did it 😊! We used first for loop to iterate over each number which are given as in our assignment, in the nested for loop, we are ranging from 0 to the number(exclusive) and multiplying each number num in the nested for loop. Once the nested for loop is exhausted, we are printing the result for the factorial of the number. In this way nested loops work. Same applies to the while loops.

27.4. break and continue#

break and continue are used to explicitly control the flow of loops by residing in the loop.

If all the objects in the iteration are completed or while condition turns falsy, the loop gets exited, but if we want to exit the loop explicitly or before completion of all objects in the loop, break comes in handy. we just need to have a break statement as break and the nearest enclosing loop in which this break is present exits.

continue in a loop stop s the execution of the next code in the current iteration and starts the next iteration of the enclosing loop.

🙈 Sometimes sentences make the explanation harder to understand. In this case, it’s better to understand using examples.

27.4.1. break#

I want to know if a particular number is present in a list or not.

my_list = [10, 23, 13, 345, 0, 8]
number_to_be_searched_for = 13

for number in my_list:
    print(f"We are checking on the number: {number}")
    if number == number_to_be_searched_for:
        print("We found the number 🏁")
        break
We are checking on the number: 10
We are checking on the number: 23
We are checking on the number: 13
We found the number 🏁

Hint

The way of searching for the number in the above code is called Linear Search. As we can see it is pretty easy to implement, but note that it isn’t efficient for huge amount of data.

Let’s get to know what has happened here 🤔? we have a list called my_list, and we needed to search for a number 13 if it is present in the my_list or not.

We have started iterating over the my_list list, once we find the number 13 in our list, we are breaking the loop. In this way, we are ensuring that it doesn’t iterate over next items unnecessarily as we already achieved what we want 😊.

How do we know if we exited the loop? As we can see that only 3 print statements saying We are checking on the number: can be found. If we don’t have a break, we would be having three more print statements as well:

# Without break
for number in my_list:
    print(f"We are checking on the number: {number}")
    if number == number_to_be_searched_for:
        print("We found the number 🏁")
We are checking on the number: 10
We are checking on the number: 23
We are checking on the number: 13
We found the number 🏁
We are checking on the number: 345
We are checking on the number: 0
We are checking on the number: 8

27.4.2. continue#

The continue statements skips execution of the code present after it and continues to execute the next iteration of the loop.

I am now in a shopping mall, picked a lot of items and now reached the billing counter, just got to remember that I just have 100 bucks with me 😱. I started looking at the cumulative total one by one being billed at the counter. I am good unless the bill crosses 100 bucks.

items_costs = (12, 3, 23, 32, 13, 38, 8, 14, 9)
cumulative_cost = 0  # Before starting the billing.

for cost in items_costs:
    cumulative_cost += cost
    if cumulative_cost <= 100:
        continue
    print(
        f"⚠️ Oops! I have breached my budget, cumulative cost is {cumulative_cost} on addition of item of cost: {cost}"
    )
⚠️ Oops! I have breached my budget, cumulative cost is 121 on addition of item of cost: 38
⚠️ Oops! I have breached my budget, cumulative cost is 129 on addition of item of cost: 8
⚠️ Oops! I have breached my budget, cumulative cost is 143 on addition of item of cost: 14
⚠️ Oops! I have breached my budget, cumulative cost is 152 on addition of item of cost: 9

In the above example I needed to drop few items ☹️ as I crossed 100 bucks. Let’s see how did the code work.

We had a tuple called items_cost which has cost of each item, we started looping each item’s cost and adding the cost to cumulative_cost and we checked if the cumulative_cost is less than or equal to 100 bucks, if true, we are in safe zone, so we are using continue statement, so that the code present next doesn’t get executed. But eventually, we are crossing 100 bucks, and so the code in the if condition doesn’t get executed as cumulative_cost <= 100 is False, hence, we see that there’s a warning print statement being executed.

27.5. Hidden treasures in looping 💰#

There are a few things that few people miss out to know about while learning loops in Python, I was one of them 😅. Let’s see what did we miss:

  • else block after loops

  • break and continue effect in loops having finally blocks

27.5.1. else block after loops#

The first question I had when I got to see code having else block after a loop What the heck is else doing here?, but later I got to know that else can be used after the loop. Well, what does it do? We just got to know about the use of break in the loops, right? If the loop explicitly exits by the keyword break, the else block doesn’t gets executed, else else block gets executed. let’s see an example.

def loop_else(value):
    my_list = [1, 234, 22, 13, 9, 3]
    for number in my_list:
        if number == value:
            print(f"value {value} found in my_list")
            break
    else:
        print(f"value {value} not found in my_list")
# 234 is present in the list, so the break statement gets executed, so else block gets skipped.
loop_else(234)
value 234 found in my_list
# 783 is not present in the list, so the break statement never gets executed, so else block gets executed.
loop_else(783)
value 783 not found in my_list

27.5.2. break and continue effect in loops having finally blocks#

If the loop consists of try-except-finally or try-finally block. If either break or continue is executed, the interpreter reaches the finally block to execute the code present in it before breaking or continuing the loop.

break

while True:
    try:
        break
    finally:
        print("in finally block")
in finally block

continue

while True:
    try:
        continue
    finally:
        print("in finally block")
        break  # Using break here to prevent an infinite loop.
in finally block