Loops in Python

Python Loops – Complete Tutorial

In Python, all statements are executed sequentially. The first statement is executed first, followed by the second, and so on. At the same time, there are many situations when you need to execute a block of code several times. To solve this problem, the Python programming language provides us with two constructs: the for loop and the while loop. Both looping constructs provide similar functionality, but they differ in syntax and condition checking. This Python loops tutorial will cover the loop, the while loop, and the flow control statements like break and continue.

Python loops – “for”

You have to use for loops when you have a block of code that you want to repeat a fixed number of times.

The for loop statement iterates over the members of a sequence (list, tuple, or strings) in order and executes your code block each time. As a Cloud Automation Engineer, you’ll be using for loops a lot while working with files in Python or processing output of cloud services APIs.

Here’s the syntax of the for loop:

for VARIABLE in SEQUENCE:
    statements

The following flow diagram visualizes the program execution process:

1. Loops in Python - Flow diagram - for loop

As an example, let’s print all EC2 instance IDs from the list:

#!/usr/bin/env python3
ec2_instance_ids = [
    'i-0e9a442e6332682dc',
    'i-0c0ce77e0b27ed800'
]
for ec2_instance_id in ec2_instance_ids:
    print(f'EC2 instance ID: {ec2_instance_id}')

Here’s an output in Cloud9 IDE:

2. Loops in Python - Cloud9 IDE - for loop example

In the example above, the for loop walks through every element of ec2_instance_ids list and assigns its value to ec2_instance_id variable so that we can use it in the print() statement.

range() class in Python

Sometimes, when we’re looping through a sequence, it is required to get any information about the element index.

In this case, you can use the range() class, which generates an immutable sequence of numbers.

Usually, we’re using range() in two ways:

  • range(stop) – where stop is the last number of the sequence
  • range(start, stop[, step]) – where start is the first value, stop is the last number in the sequence and optional step is a positive or negative number used to generate sequence numbers.

A couple of examples:

>> print(list(range(5)))
[0, 1, 2, 3, 4]
>> print(list(range(1, 3)))
[1, 2]
>> print(list(range(0, 5, 2)))
[0, 2, 4]
>> print(list(range(3, 0, -1)))
[3, 2, 1]

Iterating by index in Python

Now, as soon as we introduced a range() class, we can use this knowledge to iterate through a sequence by index.

Let’s modify our previous example to iterate ec2_instance_ids list by the list element index:

#!/usr/bin/env python3
ec2_instance_ids = [
    'i-0e9a442e6332682dc',
    'i-0c0ce77e0b27ed800'
]
for i in range(len(ec2_instance_ids)):
   print(f'Instance {i}: {ec2_instance_ids[i]}')

Here’s an output in Cloud9 IDE:

5. Loops in Python - Cloud9 IDE - for loop with index example

In the example above, the range() class will generate a sequence [0, 1] based on ec2_instance_ids array size, which is calculated by the len() function.

Else statement in Python

Like in if statement for loop can have an else statement.

Python executes else statement block after a for loop has been completely executed.

If the for loop has been interrupted by the break statement, the interpreter skips else statement block.

Here’s a statement syntax:

for VARIABLE in SEQUENCE:
    statements block 1
else:
    statements block 2

Let’s illustrate this behavior with an example:

#!/usr/bin/env python3
print(' For loop has not been interrupted '.center(50, '='))
for i in range(0, 3):
    print(i)
else:
    print('Range has been processed')
print('')
print(' For loop has been interrupted '.center(50, '='))
for i in range(0, 3):
    if i == 1:
        break
    print(i)
else:
    print('Range has been processed')

Here’s an output in Cloud9 IDE:

3. Loops in Python - Cloud9 IDE - for-else loop example

This syntax is not widely used because it is not very intuitive, even for mature Python developers.

Nested for loops in Python

Nested for loops are commonly used when we need to process nested data structures.

While automating cloud infrastructure, you may face nested loops in the code working with EC2 instances, processing SQS messages, Kinesis streams, etc.

For example, here’s an event structure of S3->SQS->Lambda integration:

{
    "Records":[
       {
          "messageId":"581db230-9853-4be3-a1fe-72c9a5b3e4d4",
          "receiptHandle":"AQEBAwV4m8sSkn5jDd1k/GBLco1znfiv+xT0KTRZdEhQE7clWhAcFlVusMR07RQsBo5ImrlIDafWwdzfX+ZqsuRQPGWE0CcsR6ga8yQTTtG6N1CpWuotJ69Ef55XILtkOMKS+7HR3Ek1oigests3bmx5eCj0QlsRR56qSpj0o1yOOLktLsUehPPTEmWmWXGGPoTc2GayxbnL6lCheolswgiMdE2u0qmbaKV6Ek3E4PyvPfzkOx8XGXIurYJCkFMGcpi0sWrus1WO+dzbm5NtOL9n8qAzjxaMyMyV+nXvy+EO1QCLu2CuX0/rhKfjoq0+txWm8tNVb27VKbwsRKrU12odmV9mbULuvKDU55CqNOMF+LZl8zdZzceegvK2wgfA8KjMmpJ5wQVWo0S8WqVpcJCKSJYhoh/XzqGde+1gQ957YR8=",
          "body":"{\"Records\":[{\"eventVersion\":\"2.1\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"us-east-1\",\"eventTime\":\"2021-04-26T23:25:17.884Z\",\"eventName\":\"ObjectCreated:Put\",\"userIdentity\":{\"principalId\":\"AWS:012850762433:admin\"},\"requestParameters\":{\"sourceIPAddress\":\"108.41.58.86\"},\"responseElements\":{\"x-amz-request-id\":\"74CMGJPKH3HA1G87\",\"x-amz-id-2\":\"c52dEWNgb6rNUs7MNY20ArZHLgtNFiRJIhREfnNAnlLsXHotTUvLS7InfWnkniuawxPgTlkOkTKZICwIgsbfdHDZKQvL0LcV\"},\"s3\":{\"s3SchemaVersion\":\"1.0\",\"configurationId\":\"tf-s3-queue-20210426224851886600000002\",\"bucket\":{\"name\":\"amaksimov-s3-sqs-demo-bucket\",\"ownerIdentity\":{\"principalId\":\"A1W385KKD8Q319\"},\"arn\":\"arn:aws:s3:::amaksimov-s3-sqs-demo-bucket\"},\"object\":{\"key\":\"6.+Beginner%27s+Guide+to+AWS+Step+functions+-+AWS+HelloWorld+example.png\",\"size\":458757,\"eTag\":\"e1148e80d0798b0e23502cbdae1fef58\",\"sequencer\":\"0060874BE06812C89A\"}}}]}",
          "attributes":{
             "ApproximateReceiveCount":"1",
             "SentTimestamp":"1619479521272",
             "SenderId":"AIDAJHIPRHEMV73VRJEBU",
             "ApproximateFirstReceiveTimestamp":"1619479521279"
          },
          "messageAttributes":{},
          "md5OfBody":"7195d8d0f011fac4dc115b59d3e86797",
          "eventSource":"aws:sqs",
          "eventSourceARN":"arn:aws:sqs:us-east-1:012850762433:amaksimov-s3-event-notification-queue",
          "awsRegion":"us-east-1"
       }
    ]
}

This message consists of a list of Records from SQS service.

Every record has a body key with another nested event from the S3 bucket represented as a string:

{
    "Records":[
       {
          "eventVersion":"2.1",
          "eventSource":"aws:s3",
          "awsRegion":"us-east-1",
          "eventTime":"2021-04-26T23:31:08.107Z",
          "eventName":"ObjectCreated:Put",
          "userIdentity":{
             "principalId":"AWS:012850762433:admin"
          },
          "requestParameters":{
             "sourceIPAddress":"108.41.58.86"
          },
          "responseElements":{
             "x-amz-request-id":"YP7DR0F7H7R1GN1S",
             "x-amz-id-2":"WYvnoGQrVxe2LfV6yr/sDsZXj/QDL0vD02WQYn9zXg3jX2iKfq83omTmcOcIiuSUk4dTmRRDrhdNNzffoi8AeSBN7RHs2ab0"
          },
          "s3":{
             "s3SchemaVersion":"1.0",
             "configurationId":"tf-s3-queue-20210426224851886600000002",
             "bucket":{
                "name":"amaksimov-s3-sqs-demo-bucket",
                "ownerIdentity":{
                   "principalId":"A1W385KKD8Q319"
                },
                "arn":"arn:aws:s3:::amaksimov-s3-sqs-demo-bucket"
             },
             "object":{
                "key":"4.+Beginner%27s+Guide+to+AWS+Step+functions+-+HelloWorld+Example.png",
                "size":9714,
                "eTag":"b21c122beffd36c0f0caabc4dbd8b16d",
                "sequencer":"0060874D3FC2FA681D"
             }
          }
       }
    ]
}

Here’s a small Python program, which processes S3 events coming from SQS queue using nested for loop:

#!/usr/bin/env python3
import json
def handler(event, context):
    for sqs_rec in event['Records']:
        s3_event = json.loads(sqs_rec['body'])
        for s3_rec in s3_event['Records']:
            s3_bucket_name = s3_rec['s3']['bucket']['name']
            s3_object_name = s3_rec['s3']['object']['key']
            print(f'Bucket name: {s3_bucket_name}', s3_bucket_name)
            print(f'Object key: {s3_object_name}')
if __name__ == '__main__':
    sqs_event = {
        "Records":[
            {
                "messageId":"581db230-9853-4be3-a1fe-72c9a5b3e4d4",
                "receiptHandle":"AQEBAwV4m8sSkn5jDd1k/GBLco1znfiv+xT0KTRZdEhQE7clWhAcFlVusMR07RQsBo5ImrlIDafWwdzfX+ZqsuRQPGWE0CcsR6ga8yQTTtG6N1CpWuotJ69Ef55XILtkOMKS+7HR3Ek1oigests3bmx5eCj0QlsRR56qSpj0o1yOOLktLsUehPPTEmWmWXGGPoTc2GayxbnL6lCheolswgiMdE2u0qmbaKV6Ek3E4PyvPfzkOx8XGXIurYJCkFMGcpi0sWrus1WO+dzbm5NtOL9n8qAzjxaMyMyV+nXvy+EO1QCLu2CuX0/rhKfjoq0+txWm8tNVb27VKbwsRKrU12odmV9mbULuvKDU55CqNOMF+LZl8zdZzceegvK2wgfA8KjMmpJ5wQVWo0S8WqVpcJCKSJYhoh/XzqGde+1gQ957YR8=",
                "body":"{\"Records\":[{\"eventVersion\":\"2.1\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"us-east-1\",\"eventTime\":\"2021-04-26T23:25:17.884Z\",\"eventName\":\"ObjectCreated:Put\",\"userIdentity\":{\"principalId\":\"AWS:012850762433:admin\"},\"requestParameters\":{\"sourceIPAddress\":\"108.41.58.86\"},\"responseElements\":{\"x-amz-request-id\":\"74CMGJPKH3HA1G87\",\"x-amz-id-2\":\"c52dEWNgb6rNUs7MNY20ArZHLgtNFiRJIhREfnNAnlLsXHotTUvLS7InfWnkniuawxPgTlkOkTKZICwIgsbfdHDZKQvL0LcV\"},\"s3\":{\"s3SchemaVersion\":\"1.0\",\"configurationId\":\"tf-s3-queue-20210426224851886600000002\",\"bucket\":{\"name\":\"amaksimov-s3-sqs-demo-bucket\",\"ownerIdentity\":{\"principalId\":\"A1W385KKD8Q319\"},\"arn\":\"arn:aws:s3:::amaksimov-s3-sqs-demo-bucket\"},\"object\":{\"key\":\"6.+Beginner%27s+Guide+to+AWS+Step+functions+-+AWS+HelloWorld+example.png\",\"size\":458757,\"eTag\":\"e1148e80d0798b0e23502cbdae1fef58\",\"sequencer\":\"0060874BE06812C89A\"}}}]}",
                "attributes":{
                    "ApproximateReceiveCount":"1",
                    "SentTimestamp":"1619479521272",
                    "SenderId":"AIDAJHIPRHEMV73VRJEBU",
                    "ApproximateFirstReceiveTimestamp":"1619479521279"
                },
                "messageAttributes":{
                    
                },
                "md5OfBody":"7195d8d0f011fac4dc115b59d3e86797",
                "eventSource":"aws:sqs",
                "eventSourceARN":"arn:aws:sqs:us-east-1:012850762433:amaksimov-s3-event-notification-queue",
                "awsRegion":"us-east-1"
            }
        ]
    }
    handler(sqs_event, {})

Here’s an output in Cloud9 IDE:

4. Loops in Python - Cloud9 IDE - nested for loop example

In the example above, we’re using:

  • For loop to walk through a list of Records of SQS event (line 6)
  • Python JSON module to convert S3 event from string to a dictionary (line 7)
  • Nested for loop to process list of Records of S3 event (line 9) and get information about S3 bucket and object key which generated the event (lines 10-11)

Python loops – “while”

In python, we’re using a while loop to execute a code block untill the test expression returns True.

Generally, we need to use a while loop when we don’t know the exact number of iterations beforehand.

Here’s the syntax of the while loop:

while TEST_EXPRESSION:
    statements

The following flow diagram visualizes the program execution process:

6. Loops in Python - Flow diagram - while loop

Here’s a list of important notes about the while loop:

  • In the while loop, the test expression is checked first, and the body of the loop is entered only if TEST_EXPRESSION equals True.
  • After every iteration, the test expression is checked again, and this process continues until the TEST_EXPRESSION returns False.
  • Python interprets any non-zero value returned in TEST_EXPRESSION as True.
  • None and 0 are interpreted as False.

Iterating by list index in Python

Let’s implement iteration over EC2 instances list using while loop:

#!/usr/bin/env python3
ec2_instance_ids = [
    'i-0e9a442e6332682dc',
    'i-0c0ce77e0b27ed800'
]
instance_number = 0
while instance_number < len(ec2_instance_ids):
    print(f'EC2 instance ID: {ec2_instance_ids[instance_number]}')
    instance_number += 1

Here’s an output in Cloud9 IDE:

7. Loops in Python - Cloud9 IDE - while loop example

Processing lists using iterator in Python

In addition to indexes, you can use iterators for processing while loop in Python.

There’s no difference between iterators and indexes for small data sets, but for a large data sets, usage of iterators saves you memory and execution time (StackOverflow).

Here’s an example of using iterator for processing the same list of EC2 instances:

#!/usr/bin/env python3
ec2_instance_ids = [
    'i-0e9a442e6332682dc',
    'i-0c0ce77e0b27ed800'
]
iterator = iter(ec2_instance_ids)
while True:
    try:
        ec2_instance_id = next(iterator)
        print(f'EC2 instance ID: {ec2_instance_id}')
    except StopIteration:
        break

Here’s an output in Cloud9 IDE:

8. Loops in Python - Cloud9 IDE - while loop with iterator example

A couple of comments about the example above:

  • We’re making the list of EC2 instances iterable by using iter() function (line 8).
  • An infinite while loop (line 10) is walking through the list of EC2 instance IDs.
  • In the try block (line 11), we fetch the next element of ec2_instance_ids list with next() function (line 12).
  • When the next() function raises the StopIteration exception (line 12), we’re breaking the loop execution (lines 14-15)

Nested while loops in Python

In the same way, as nested for loop, you can use nested while loops.

while TEST_EXPRESSION_1:
    statements_block_1
    while TEST_EXPRESSION_2:
        statements_block_2
    
    statements_block_3

In the syntax example above, while loop on line 1 executes:

  • statements_block_1 (line 2)
  • Nested while loop with its own TEST_EXPRESSION_2 (line 4) and statements_block_2 (line 5)
  • statements_block_3 (line 7)

Else statement in forl loop in Python

Similar to the else statement in the for loop, you can use the else statement with the while loop in the same way.

The same rules will apply:

#!/usr/bin/env python3
ec2_instance_ids = [
    'i-0e9a442e6332682dc',
    'i-0c0ce77e0b27ed800'
]
print(' While loop has not been interrupted '.center(50, '='))
instance_number = 0
while instance_number < len(ec2_instance_ids):
    print(f'EC2 instance ID: {ec2_instance_ids[instance_number]}')
    instance_number += 1
else:
    print('Done!')
print(' While loop has been interrupted '.center(50, '='))
iterator = iter(ec2_instance_ids)
while True:
    try:
        ec2_instance_id = next(iterator)
        print(f'EC2 instance ID: {ec2_instance_id}')
    except StopIteration:
        break
else:
    print('Done!')

Here’s an output in Cloud9 IDE:

9. Loops in Python - Cloud9 IDE - while-else loop example

Flow control in Python

Flow control statements change the flow execution normal behavior.

Three statements allow us to control the loop execution process:

  • continue
  • break
  • pass

Let’s introduce them one by one.

Continue in Python

The continue statement returns the control to the beginning of the loop.

In most Python programs, we use continue statement to skip processing of a sequence element, for example:

#!/usr/bin/env python3
for i in range(4):
    if i == 2:
        continue
    print(i)
print('End of the program')

Here’s an output in Cloud9 IDE:

12. Loops in Python - Cloud9 IDE - continue example

Break in Python

The break statement immediately exits the loop.

This statement is commonly used in complex search operations to break the search process if the result has been found:

#!/usr/bin/env python3
for i in range(4):
    if i == 2:
        break
    print(i)
print('End of the program')

Here’s an output in Cloud9 IDE:

11. Loops in Python - Cloud9 IDE - break example

Pass in Python

The pass statement allows us to declare empty loops, functions, classes, and if statements.

In real life, we use this statement when we know that we need a loop, function, or class but do not want to implement it yet.

For example, this is a valid Python program:

#!/usr/bin/env python3
ec2_instance_ids = [
    'i-0e9a442e6332682dc',
    'i-0c0ce77e0b27ed800'
]
for i in range(len(ec2_instance_ids)):
    # Implement code to process instances
    pass
print('End of the program')

Here’s an output in Cloud9 IDE:

10. Loops in Python - Cloud9 IDE - pass example

Similar Posts