Python Basics #15 — for Loop

7 min read

In today’s lesson we’ll cover the for loop.

Python’s for loop is used to iterate over a collection of data sequentially. It’s similar to while but in most cases more convenient — and the more commonly used of the two.

Any sequence-type object can be used in a for loop. To check whether an object is iterable, use the iter function. Sequence-type objects usable in a for loop include strings, lists, dictionaries, tuples, sets, and range objects.

Sequence-type objects usable in a for loop

  • String
  • List
  • Dictionary
  • Tuple
  • Set
  • Range

Objects you can’t use in a for loop — non-sequence types — include int, float, bool, None, and function objects.

Objects NOT usable in a for loop

  • Integer
  • Float
  • Boolean
  • None
  • Function

As mentioned, the iter function tells you whether an object can be used in a for loop. If passing the object to iter returns an iterator object, it’s iterable; if it raises a TypeError, it isn’t.

Verify with iterable objects:

# objects usable in a for loop
my_string = 'abc'
my_list = [1, 2, 3]
my_dict = {'a': 1, 'b': 2}
my_set = {'a', 'b', 'c'}
my_range = range(10)

print('String: {}'.format(iter(my_string)))
print('List: {}'.format(iter(my_list)))
print('Dictionary: {}'.format(iter(my_dict)))
print('Set: {}'.format(iter(my_set)))
print('Range: {}'.format(iter(my_range)))
String: <str_iterator object at 0x000001F326934BB0>
List: <list_iterator object at 0x000001F3247614F0>
Dictionary: <dict_keyiterator object at 0x000001F3274E0860>
Set: <set_iterator object at 0x000001F3274EFC00>
Range: <range_iterator object at 0x000001F326908D10>

All iterable objects passed to iter return an iterator object.

Now let’s verify with non-iterable objects:

# objects NOT usable in a for loop
my_integer = 1
my_float = 1.234
my_bool = True
my_none = None
def my_func():
pass

print('Integer: {}'.format(iter(my_integer)))

TypeError: 'int' object is not iterable

Non-iterable objects passed to iter raise a TypeError. Try float, bool, None, and the function object yourself.

Run a for loop on a string (an iterable):

my_string = 'abc'

for letter in my_string:
print(letter)

a
b
c

As the loop runs, the variable letter is assigned each character one at a time.

How does a for loop work internally? You need to understand iter and next first.

Pass a string to iter to create a str_iterator, then call __next__ to get characters one by one:

iter_obj = iter('abc')

print(iter_obj)
print(iter_obj.__next__())
print(iter_obj.__next__())
print(iter_obj.__next__())
print(iter_obj.__next__())

<str_iterator object at 0x000001F324761250>
a
b
c
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
in
5 print(iter_obj.__next__())
6 print(iter_obj.__next__())
----> 7 print(iter_obj.__next__())

a, b, c print sequentially, then a StopIteration is raised when there’s nothing left. iter takes a sequence object and returns an iterator object. The iterator has a __next__ method; calling it returns the next element. When there’s nothing left to return, it raises StopIteration.

Inside a for loop you can use two helper keywords: continue and break. continue skips the current iteration; break exits the loop. Let’s use both:

my_list = ['one', 'two', 'three', 'skip', 'four', 'five']

for num in my_list:
if num == 'skip':
continue  # skip when the value is 'skip'

    print(num)

    if num == 'four':
        break  # exit the loop when the value is 'four'

one
two
three
four

When using for loops you’ll sometimes want to unpack items. For example, when iterating over a list of lists, the inner list is bound to a single variable:

list_1 = [[1, 2], [3, 4], [5, 6]]

for i in list_1:
print(i)

[1, 2]
[3, 4]
[5, 6]

But if you declare two variables in the for, each inner-list item gets bound to its own variable. That’s unpacking:

list_1 = [[1, 2], [3, 4], [5, 6]]

for i, j in list_1:
print(i, j)

1 2
3 4
5 6

You could also use a nested for loop to access each item, but with a small inner length, unpacking is more convenient.

Unpacking works for more than two items too:

list_2 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

for i, j, k in list_2:
print(i, j, k)

1 2 3
4 5 6
7 8 9

If the number of unpack targets and items don’t match, you get an error:

list_2 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

for i, j in list_2:
print(i, j)

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-20-19b25bdbc030> in <module>
2 list_2 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3
----> 4 for i, j in list_2:
5     print(i, j)

ValueError: too many values to unpack (expected 2)

Now let’s see how to use a dictionary in a for loop. Define a small dict and run a for loop:

my_dict = {
'a': 1,
'b': 2,
'c': 3
}

for i in my_dict:
print(i)

a
b
c

Iterating a dictionary yields keys, not values. To get the value, look it up using the returned key:

my_dict = {
'a': 1,
'b': 2,
'c': 3
}

for key in my_dict:
print('{}: {}'.format(key, my_dict[key]))

a: 1
b: 2
c: 3

Or use the items method:

my_dict = {
'a': 1,
'b': 2,
'c': 3
}

for i in my_dict.items():
print(i)

('a', 1)
('b', 2)
('c', 3)

items returns each (key, value) pair as a tuple. With unpacking:

my_dict = {
'a': 1,
'b': 2,
'c': 3
}

for k, v in my_dict.items():
print('{}: {}'.format(k, v))

a: 1
b: 2
c: 3

Sets are also iterable. Sets are unordered, so the iteration order in for doesn’t match insertion order:

my_set = {'a', 'b', 'c'}

for i in my_set:
print(i)

c
b
a

Finally, the range object.

The range function is commonly used when you want to iterate a specific number of times. To print 1 through 10:

for i in range(1, 11):
print(i)

1
2
3
4
5
6
7
8
9
10

A common coding-test problem is to use a loop to print a multiplication table. Using for and range:

for i in range(1, 10):
for j in range(2, 10):
result = '{} x {} = {}'.format(j, i, j * i)
print('{:10s}'.format(result), end='\\t')
print()

2 x 1 = 2 	3 x 1 = 3 	4 x 1 = 4 	5 x 1 = 5 	6 x 1 = 6 	7 x 1 = 7 	8 x 1 = 8 	9 x 1 = 9
2 x 2 = 4 	3 x 2 = 6 	4 x 2 = 8 	5 x 2 = 10	6 x 2 = 12	7 x 2 = 14	8 x 2 = 16	9 x 2 = 18
2 x 3 = 6 	3 x 3 = 9 	4 x 3 = 12	5 x 3 = 15	6 x 3 = 18	7 x 3 = 21	8 x 3 = 24	9 x 3 = 27
2 x 4 = 8 	3 x 4 = 12	4 x 4 = 16	5 x 4 = 20	6 x 4 = 24	7 x 4 = 28	8 x 4 = 32	9 x 4 = 36
2 x 5 = 10	3 x 5 = 15	4 x 5 = 20	5 x 5 = 25	6 x 5 = 30	7 x 5 = 35	8 x 5 = 40	9 x 5 = 45
2 x 6 = 12	3 x 6 = 18	4 x 6 = 24	5 x 6 = 30	6 x 6 = 36	7 x 6 = 42	8 x 6 = 48	9 x 6 = 54
2 x 7 = 14	3 x 7 = 21	4 x 7 = 28	5 x 7 = 35	6 x 7 = 42	7 x 7 = 49	8 x 7 = 56	9 x 7 = 63
2 x 8 = 16	3 x 8 = 24	4 x 8 = 32	5 x 8 = 40	6 x 8 = 48	7 x 8 = 56	8 x 8 = 64	9 x 8 = 72
2 x 9 = 18	3 x 9 = 27	4 x 9 = 36	5 x 9 = 45	6 x 9 = 54	7 x 9 = 63	8 x 9 = 72	9 x 9 = 81

A multiplication table built easily.

That wraps up today’s lesson. In the next lesson we’ll cover functions.

X