Iterators & Zip
enumerate, zip, and argument unpacking.
enumerate
Not infrequently, you’ll want to iterate over a list and use both its elements and their indexes:
# not Pythonic
for i in range(len(documents)):
document = documents[i]
do_something(i, document)
# also not Pythonic
i = 0
for document in documents:
do_something(i, document)
i += 1The Pythonic solution is enumerate, which produces tuples (index, element):
for i, document in enumerate(documents):
do_something(i, document)Similarly, if we just want the indexes:
for i in range(len(documents)): do_something(i) # not Pythonic
for i, _ in enumerate(documents): do_something(i) # PythonicWe’ll use this a lot.
zip and Argument Unpacking
Often we will need to zip two or more lists together. zip transforms multiple lists into a single list of tuples of corresponding elements:
list1 = ['a', 'b', 'c']
list2 = [1, 2, 3]
zip(list1, list2) # is [('a', 1), ('b', 2), ('c', 3)]If the lists are different lengths, zip stops as soon as the first list ends.
You can also "unzip" a list using a strange trick:
pairs = [('a', 1), ('b', 2), ('c', 3)]
letters, numbers = zip(*pairs)The asterisk performs argument unpacking, which uses the elements of pairs as individual arguments to zip. It ends up the same as if you’d called:
zip(('a', 1), ('b', 2), ('c', 3))which returns [('a','b','c'), ('1','2','3')].
You can use argument unpacking with any function:
def add(a, b): return a + b
add(1, 2) # returns 3
add([1, 2]) # TypeError!
add(*[1, 2]) # returns 3It is rare that we’ll find this useful, but when we do it’s a neat trick.