Iterable Objects#

Tuples, lists, and dictionaries are examples of iterable objects. These are objects which allow for consecutive evalution of their items. There exist more types of iterable objects in Python and we may define new iterable objects by implementing suitable dunder methods.

For loops#

We briefly mentioned for loops in the Crash Course. Now we add the details.

Basic Iteration#

For loops allow to iterate through iterable objects of any kind, especially tuples, lists and dictionaries.

colors = ('red', 'green', 'blue', 'yellow')

for color in colors:
    print(color)
red
green
blue
yellow

The indented code below the for keyword is executed as long as there are remaining items in the iterable object. In the example above the name color first points to colors[0], then, in the second run, to colors[1], and so on.

This index-free iteration is considered pythonic: it’s much more readable than indexing syntax and directly fulfills the purpose of iteration, while indexing in most cases is useless additional effort.

Note

The range built-in function we saw in the crash course is not part of the for loop’s syntax. Instead, it’s a built-in function returning an iterable object which contains a series of integers as specified in the arguments passed to the range function. The returned object is of type range.

The range function takes up to three arguments: the starting index, the stopping index plus 1, and the step size. Step size defaults to 1 if omitted. If only one argument is provided, it’s interpreted as stopping index (plus 1) and start index is set to 0.

Iteration With Indices#

If next to the items themselve also their index is needed inside the loop, use the built-in function enumerate and pass the iterable object to it. The enumerate function will return an iterable object which yields a 2-tuple in each iteration. The first item of each tuple is the index, the second one is the corresponding object.

colors = ('red', 'green', 'blue', 'yellow')

for index, color in enumerate(colors):
    print(str(index) + ': ' + color)
0: red
1: green
2: blue
3: yellow

Iterating Over Multiple Lists in Parallel#

Being new to Python one is tempted to indexing for iteration over multiple lists in parallel:

# non-pythonic!

names = ['John', 'Max', 'Lisa']
surnames = ['Doe', 'Muller', 'Lang']

for i in range(len(names)):
    print(names[i] + ' ' + surnames[i])
John Doe
Max Muller
Lisa Lang

For iterating over multiple lists at the same time pass them to zip. This built-in function returns an iterable objects which yields tuples. The first tuple consists of the first elements of all lists, the second of the second elements of all lists and so on. The returned iterable object has as many items as the shortest list.

names = ['John', 'Max', 'Lisa']
surnames = ['Doe', 'Muller', 'Lang']

for name, surname in zip(names, surnames):
    print(name + ' ' + surname)
John Doe
Max Muller
Lisa Lang

Comprehensions#

Applying some operation to each item of an iterable object can be done via for loops. But there are handy short-hands known as list comprehensions and dictionary comprehensions.

List Comprehensions#

General syntax is

[new_item for item in some_list]

The following code snipped generates a list of squares from a list of numbers.

some_numbers = [2, 4, 6, 8]

squares = [x * x for x in some_numbers]

print(squares)
[4, 16, 36, 64]

Like in for loops also multiple lists are possible:

some_numbers = [2, 4, 6, 8]
more_numbers = [1, 2, 3, 4]

products = [x * y for x, y in zip(some_numbers, more_numbers)]

print(products)
[2, 8, 18, 32]

Nested for loops work, too:

[new_item for item_a in list_a for item_b in list_b]

Same principles (zipping and nesting) work for more than two lists, too.

Note

List comprehensions have two advantages compared to for loops:

  • For small loops a one-liner is more readable than several lines.

  • In most cases list comprehensions are faster.

Dictionary Comprehensions#

Dict comprehensions look very similar to list comprehensions. General syntax:

{new_key: new_value for some_item in some_iterable}

Example modifying values only:

person = {'name': 'John', 'surname': 'Doe', 'eyes': 'brown'}

# enclose all values with star symbols
stars = {key: '*' + value + '*' for key, value in person.items()}

print(stars)
{'name': '*John*', 'surname': '*Doe*', 'eyes': '*brown*'}

Example modifying keys and values of a dictionary:

person = {'name': 'John', 'surname': 'Doe', 'eyes': 'brown'}

# enclose keys and values with star symbols
stars = {'*' + key + '*': '*' + value + '*' for key, value in person.items()}

print(stars)
{'*name*': '*John*', '*surname*': '*Doe*', '*eyes*': '*brown*'}

Note

Dictionary comprehensions may be used to create new dictionaries from arbitrary iterable objects. For instance we could loop over the zipped lists, one holding the keys and one holding the values.

Conditional Comprehensions#

List and dictionary comprehensions can be extended by a condition: simply append if some_condition to the comprehension.

some_numbers = [2, 4, 6, 8]
more_numbers = [1, 0, 2, 3]

quotients = [x / y for x, y in zip(some_numbers, more_numbers) if y != 0]

print(quotients)
[2.0, 3.0, 2.6666666666666665]

The list (or dictionary) comprehension drops all items not satisfying the condition.

Manual iteration#

Python has a built-in function next which allows to iterate through iterable objects step by step. For this purpose we first have to create an iterator object from our iterable object. This is done by the built-in function iter. Then the iterator object is passed to next. The iterator object takes care about what the next item is.

a = iter([3, 2, 5])

print(next(a))
print(next(a))
print(next(a))
3
2
5

Creation of the intermediate iterator object is done automatically if iterable objects are used in for loops and comprehensions.

The in keyword#

To test whether an object is contained in an iterable object, we my use the in keyword.

a = [1, 5, 6, 8]
print(1 in a)
print(10 in a)
True
False
a = {'name': 'Jon', 'age': 42}
print('name' in a)
print('Jon' in a)
print('Jon' in a.values())
True
False
True

The counterpart to in is not in.

Note

Conditions a not in b and not a in b are equivalent. The first uses the not in operator, while the second uses in and then applies the logical operator not to the result.