Chapter 7: for-loops

Generic badge Open this in Colab

The for loop

In on of the previous chapter we have defined the word list word_list:

word_list = ["my", "name", "is", "Gandalf"]
print(word_list)

['my', 'name', 'is', 'Gandalf']

We also learned, that we can access individual entries via indexing:

print(word_list[0])
print(word_list[1])
print(word_list[2])
print(word_list[3])

my
name
is
Gandalf

Instead of printing out each entry by indexing each element manually, we can automatize this task with a so-called for-loop:

for any_index in any_list_of_length_N:
    # N-times iteration of your command(s)
    # that command can even use the any_index-value
  • any_list_of_length_N is any list, over which we’d like to iterate
  • any_index is an iterator-placeholder, that gets/becomes each value of the list step-by-step with each iteration
  • the commands followed after the “:” will be executed as many times as any_list_of_length_N has entries
# for-loop example 1:
for current_word in word_list:
    print(current_word)

my
name
is
Gandalf

As you can see, current_word becomes step-by-step the entries of the pre-defined word_list list-variable.

Code indentation

Python relies on indentation (whitespace at the beginning of a line) to define the scope of code blocks as for for-loops (but also for if-conditions and function definitions). The for-block and any other code block doe not require a specific “end”-indicator, just un-indent after you finished the block.

Exercise 1

  1. Create a new script and define the number list number_list = [67, 68, 69, 70].
  2. Write a for-loop, that iterates over number_list and prints out each element entry-by-entry.
# Your solution here:

current entry: 67
current entry: 68
current entry: 69
current entry: 70

Toggle solution
# Solution 1:
number_list = [67, 68, 69, 70]
for entry in number_list:
    print(f"current entry: {entry}")

The range command

Sometimes you don’t want the iterator to become directly the entries of the iterating list, but an index value. This can be achieved via the range command paired with the len command:

# for-loop example 2:
print(f"the length of my list is {len(word_list)}")

for i in range(0, len(word_list), 1):
    print(f"at index {i} there is "
          f"the entry: {word_list[i]}")

the length of my list is 4
at index 0 there is the entry: my
at index 1 there is the entry: name
at index 2 there is the entry: is
at index 3 there is the entry: Gandalf

The range command accepts three arguments: range(start, stop, step):

  • generates an iterator from start-value (included) to stop-value (not included) in the given integer step-size.
  • skipping the start-value let’s range by default start at 0.
  • skipping the step-value let’s range by default step in step-sizes of 1.

E.g., range(0, 4, 1) is identical to range(4).

The output of range is nothing that you can print out or use as a variable - it’s a specific iterator-construct for the for-loop. But there is a workaround to get (and validate) the iterator entries generated by range: list(range(start, stop, step)). For example:

print(range(10))

range(0, 10)

my_new_list = list(range(10))
print(f"my_new_list: {my_new_list}")

my_new_list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

my_new_list_2 = list(range(3,10,2))
print(f"my_new_list_2: {my_new_list_2}")

my_new_list_2: [3, 5, 7, 9]

my_new_list_3 = list(range(len(word_list)))
print(f"my_new_list_3: {my_new_list_3}")

my_new_list_3: [0, 1, 2, 3]

Exercise 2

  1. Create a new cell in your script from the previous Exercise 1.
  2. Create a new number list number_list_2 that ranges from 3 to 13 in the step-size of 1 (use the range and list command).
  3. Write a for-loop, that iterates over number_list_2 and prints out each element entry-by-entry and its according index, by using the range and len command.
  4. Modify the step-size to 2 and re-run you script/cell.
# Your solution 2.1-2.2 here:

number_list_2: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
the length of number_list_2: 11

# Your solution 2.3 here:

0. index has the value 3
1. index has the value 6
2. index has the value 9
3. index has the value 12

# Your solution 2.4 here:

Toggle solution
# Solution 2:
number_list_2 = list(range(3, 14,1))
print(f"number_list_2: {number_list_2}")
print(f"the length of number_list_2: {len(number_list_2)}")
print("")

step_size = 3

for i in range(0, len(number_list_2), step_size):
    print(f"{i}. index has the value {number_list_2[i]}")
Example use-case
# Example use-case:
number_list_3 = list(range(5, 16,1))
print(f"{len(number_list_2)}, {len(number_list_3)}")
print("")

step_size = 1

for i in range(0, len(number_list_2), step_size):
    print(f"{number_list_2[i]} + {number_list_3[i]} = "
          f"{number_list_2[i] + number_list_3[i]}")

11, 11
3 + 5 = 8
4 + 6 = 10
5 + 7 = 12
6 + 8 = 14
7 + 9 = 16
8 + 10 = 18
9 + 11 = 20
10 + 12 = 22
11 + 13 = 24
12 + 14 = 26
13 + 15 = 28

The enumerate function

enumerate is another useful function, which provides you with both, the current index and the current value of a given list over which you are iterating:

enumerate(iterable, start=0)

with

  • iterable: any object that supports iteration (e.g., lists)
  • start: the index value from which the counter is to be started, by default it is 0
# Example with enumerate command:
my_list = ['apple', 'windows', 'android', 'linux']
for counter, value in enumerate(my_list):
    print(f"counter {counter} relates to entry: {value} = "
          f"{my_list[counter]}")

counter 0 relates to entry: apple = apple
counter 1 relates to entry: windows = windows
counter 2 relates to entry: android = android
counter 3 relates to entry: linux = linux

or

for counter, value in enumerate(my_list, 3):
    print(f"counter {counter} relates to entry: {value}")

counter 3 relates to entry: apple
counter 4 relates to entry: windows
counter 5 relates to entry: android
counter 6 relates to entry: linux

List comprehension

List comprehension is an elegant way of defining or creating sets in Python that is very close to the mathematical notation of sets. Let’s express for example the expression

$$ \left[\; x^2 \; |\; x \in [0, 1, 2, 3, 4] \;\right] $$

(reads: the set of x to the square such that x is an element of the list 0, 1, 2, 3, 4.)

via list comprehension:

result = [ (x*x) for x in [0, 1, 2, 3, 4]]
print(result)

[0, 1, 4, 9, 16]

or even shorter:

print([ (x*x) for x in [0, 1, 2, 3, 4]])

[0, 1, 4, 9, 16]

# instead of:
for x in [0, 1, 2, 3, 4]:
    #print(x*x)
    print(x**2)

0
1
4
9
16

Note: You have to put the list comprehension into straight brackets, which converts the result into a list. Otherwise the output will be just a so-called “generator object”:

print( (x*x) for x in [0, 1, 2, 3, 4])

<generator object <genexpr> at 0x7fed3801a430>

List comprehension also works with pre-defined lists (sequences):

word_list = ["hello", "this", "is", "a", "list", "comprehension"]
print( [word for word in word_list])

['hello', 'this', 'is', 'a', 'list', 'comprehension']

Summary

The advantage of list comprehension is the reduction of the complexity of your code: you end up with fewer lines in your script. However, this complexity reduction, i.e., putting many commands into one line, might make your code difficult to oversee, especially when you just started to learn programming.

updated: