Python Loop-a-loop : and we comprehend

Python Loop-a-loop : and we comprehend

the name holds true to its meaning, if the question is what is a loop?

Yes it is like circling around the same thing again and again. It is similar to merry go round, where the number of chairs that we start with, is the number of times participants play or go around them.

On our systems, the purpose is to execute same set of instructions a certain number of times. Of course the outcomes isn't expected to be the same every time since the values that we operate with every time isn't the same. It might be following a pre-defined pattern (as in set increments or decrements) or go over an ordered set of values stored in a list.

For Loop 0 1 2 3 4 While Loop counter < 5 Break Continue

Fundamentally, the number of times we need to go over is either already known, or is logically concluded basis some condition. This fundamentally gives rise to two types of loops:

  1. For Loops: used when we know how many times are we supposed to go over same piece of code- usually employed to go over the items in a sequence like string, list etc.
  2. While Loops: used to keep the code running till the time a condition is being met or is found to be logically holding true.

Well come to think of it we can use just both for implementing loops- but over time its just become second in nature to programmers, when it comes to solving use cases. We just tend to pick what is more handy, and that's how Python's own syntax has also evolved over time!

Alright time to go over a few examples, that way we can expect to grasp it faster:

#basic for loop with range
#range generates a sequence of numbers that we can use to iterate over

for i in range(5):
    print(f"Iteration {i}") #prints starting 0 through to 4

#lets loop through a sequence or collection
fruits= ["apple", "banana", "cherry"]
for fruit in fruits:
    print(f"Processing {fruit}")

#while loop 
counter= 0
while counter < 5:
    print (f"Counter is {counter}")
    counter + = 1 #same as counter= counter + 1

There are two special statements or commands that we have in Python (not just in python but this one's also there in few other languages). They provide for overriding the usual flow or number of executions basis whatever logic we give to it. Here they are:

  1. break: moment this is encountered, code execution skips the loop altogether
  2. continue: moment this one's encountered, code execution moves over to our for / while control statement, skipping over whatever was to come as remaining set of statements

cool, now lets go over some examples

#break and continue
for i in range(5):
    if i == 4:
        break
    print(i) #this is only able to print 0,1,2,3. since we break out of the loop at 4

for i in range(5):
    if i == 2:
        continue
    print(i) #this gets to print 0 to 4 but, not 2 since at 2 we continue to the next iteration and skip the print statement altogether

It's time we introduce Nested Loop. Loop statements enclosed within another loop statement- that is what nested is about. This usually comes in handy when the inner loop needs to work on a certain set of values that is dependent on the outer iteration active during the execution.

a simple example could be certain routine activities that we carry out everyday- or rather plan to 😀 . It goes like this:

#the planned patterns in our daily life
daysOfWeek =  ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
morningRitual = ["wake up", "shower", "hydrate"]

#nest this 
for day in daysOfWeek:
    print(f"\nWaking up to {day}:")
    for ritual in morningRitual:
        print(f"Let's do {ritual} now")

Next up, mostly useful by its ease of producing logs, is looping with enumerate. Let's take up a simple example then dissect what happens under the hood:

#enumerate
fruits = ["apple","banana","kiwi"]
for index, fruit in enumerate(fruits):
    print(f"at index {index} we got {fruit}")

#prints this
at index 0 we got apple
at index 1 we got banana
at index 2 we got kiwi

Under the hood?

  • enumerate() returns or gives us a pair of values- the index and the item from list
  • the use of syntax index, fruit is using python's unpacking to split every pair returned from enumerate into two variables
  • by default enumerate starts counting from 0 unless we specify a start value like enumerate(fruits, start=1)

Finally, Comprehension- what is this? This is shorter, hence better way of putting a longer set of loop commands into concise form factor. Comes in handy for lists, dictionary and even sets. Look out for generator comprehension!

Lets cite a few here:

#list comprehension
numbers = [1,2,3,4,5]

#simple transformation
squares = [num * num for num in numbers] # equals [1,4,9,16,25]

#conditional transformation
evenSquares = [num * num for num in numbers if num % 2 == 0] # equals [4,16]

#dictionary comprehension
numToSquares = {num : num * num for num in numbers} # equals {1:1,2:4,3:9,4:16,5:25}

#set comprehension
uniqueSquares = {num * num for num in numbers} # equals {1,4,9,16,25}

#generator comprehension
squareGen = (num * num for num in numbers) # creates an iterator instead of tuple 
List Comprehension [1, 2, 3, 4, 5] [1, 4, 9, 16, 25] Dict Comprehension [1, 2, 3] x:x² {1:1, 2:4, 3:9} Generator Comprehension Yields values one at a time (x*x for x in range(5))

Among all the examples above, you might have noted there is't a tuple comprehension. Why? because Python makers didn't want to introduce confusion into the syntax. a few notables:

  • parenthesis are primarily used for grouping expressions
  • converting to a tuple is easy just mention tuple outside as in, tuple(num * num for num in numbers)
  • we can loop over a generator, but once complete ie exhausted looping, the same generator can't be reused
  • we can access values by using next() as in next(squareGen)
  • generators are more memory efficient than tuples. You get the reasons why..

A few practical examples before we close:

data = [
    {"name": "Alice", "age": 25},
    {"name": "Bob", "age": 30},
    {"name": "Charlie", "age": 35},
    ]

#extract names of folks over 28 years
over28 = [person["name"] for person in data if person["age"] > 28]

#nested comprehension
#lets create a matrix of multiplication table
matrix = [[i*j for j in range(1,6)] for i in range(1,6)] #guess this one

Alright, this is where we end today. Hope you had a head start. In our next letter we will uncover Functions! till then, have fun learning.