Chapter 9 Iterations

In this section we’ll explore reiteration using iterable objects and iterators

We got already pretty far in our Python journey without looking at looping. That’s not because it’s not necessary or useful, but we needed to get a solid foundation on the basic concepts first. Let’s take a look at iterations here.

9.1 Iterators

The most common type of iteration is the for loop. Like functions indentation is with 4 spaces, not a tab.

We can iterate over elements in a list:


# Display names in a list:
letters = ['A', 'B', 'C']
for names in letters:
    print(names)
## A
## B
## C

Over characters in a string

# Characters in a string
for letter in 'Rick':
    print(letter)
## R
## i
## c
## k

Or over a sequence of numbers

# over a sequence of numbers
for i in range(4):
    print(i)
## 0
## 1
## 2
## 3

This is because list, strings and ranges are all iterable objects, but so are dictionaries and even file connections. All that means is that these objects have an associated iter() method.

An iterator is an object that has an associated next() method. To create an iterator from iterable, use the Builtin iter() function:

To summarize:

  • An iterable is an object that can return an iterator
  • An iterator is an object that keeps state and produces the next value when you call next() on it.
word = 'Python'

it = iter(word)

next(it)
## 'P'
next(it)
## 'y'
next(it)
## 't'
next(it)
#next(it)
## 'h'

After the fourth iteration there are no more steps, we get a StopIteration error.

We can print all values of an iterator in one go with the star (aka “splat”) operator *.

word = 'Python'

it = iter(word)

print(*it)
## P y t h o n
print(*it)

But you can only do it once.

Recall that dictionaries are also iterables. The items() method unpacks the items in a dictionary into key/value pairs. We loop over two items then, and separate them using a comma.

people = {'Rick': 'Scavetta', 'Mary': 'Shelly'}

for key, value in people.items():
    print(key, value)
## Rick Scavetta
## Mary Shelly

We can also loop over elements in files (not executed):

file = 'open.txt'

it = iter(file)

print(next(it))
print(next(it))

We can use the iter() function to get an iterator, as well as the next() function to retrieve the values one by one from the iterator.

Some functions can take iterators and iterables as arguments, like list() and sum().

# Create a range object: values
values = range(10, 21)
# Print the range object
values
## range(10, 21)
# Create a list of integers: values_list
values_list = list(values)
# Print values_list
values_list
## [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
# Get the sum of values: values_sum
values_sum = sum(values)
# Print values_sum
values_sum
## 165

9.1.1 Common functions when working with iterables

Two functions that you’ll encounter when using iterables are:

  • enumerate(), to add a counter to any iterable, and
  • zip(), to stitch together an arbitrary number of iterables.

For example, to add a counter:

names = ['A', 'B', 'C']
e = enumerate(names)
print(type(e))
## <class 'enumerate'>

This consists of pairs containing the original values and their index position. To see what that means, use list() to convert this to a list of tuples.

e_list = list(e)
e_list
## [(0, 'A'), (1, 'B'), (2, 'C')]

Actually, the enumerate object is itself an iterable and we can loop over it. Notice how we use two values for looping, like we did with dictionaries.


names = ['A', 'B', 'C', 'D', 'E', 'F']

for index, value in enumerate(names):
    print(index, value)
## 0 A
## 1 B
## 2 C
## 3 D
## 4 E
## 5 F

We can even control the stating of the index using the start argument:


for index, value in enumerate(names, start = 3):
    print(index, value)
## 3 A
## 4 B
## 5 C
## 6 D
## 7 E
## 8 F

To summaries, enumerate() returns an enumerate object that produces a sequence of tuples, and each of the tuples is an index/value pair.

We’ve already seen zip() in action. This function accepts an arbitrary number of iterables and returns an iterator of tuples. For example, with two lists:

letter = ['A', 'B', 'C', 'D', 'E', 'F']
names = ['Aardvark', 'Bear', 'Cat', 'Dog', 'Elephant', 'Fox']

z = zip(letter, names)

# type(z) 
## <class 'zip'>
z
## <zip object at 0x7f97a8cb5448>

Alternatively:


for z1, z2 in zip(letter, names):
    print(z1, z2)
## A Aardvark
## B Bear
## C Cat
## D Dog
## E Elephant
## F Fox

Exercise 9.1 Get a unique list of values in the group column of plant_growth. Previously we just used the .groupby() to apply an aggregration function to the weights, as an example of doing this manually, loop through the DataFrame and calculate the mean weight according to each group.

9.2 Wrap-up

In this section we saw how Python uses for loop and iterators to keep track of values. But don’t forget the power of broadcasting that we saw with pandas DataFrames.