One of the main differences between Python 3.0 and Python 2.X is the stronger emphasis on iterators. In addition to the iterators associated with built-in types such as files and dictionaries, the dictionary methods keys, values and items return iterable objects in Python 3.0, as do some of the built-in functions such as zip and range.
The Zip Function
As an example, consider the zip function. The Python zip function returns an iterator of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. For example:
>>> x = [1, 2, 3] >>> y = [4, 5, 6] >>> zipped = zip(x, y) >>> list(zipped) [(1, 4), (2, 5), (3, 6)]
Note that if there is a size mismatch, the iterator returned will only return as many tuples as the smallest sequence:
>>> z = [7, 8] >>> zipped = zip(x, z) >>> list(zipped) [(1, 7), (2, 8)]
These examples involve combining two lists, but any iterable sequence can be used in a zip object. For example, imagine we want to generate a series of tuples containing one file line in each tuple as well as the file line number:
>>> x = range(1,5) >>> f = open('simple.py') >>> zipped = zip(x,f) >>> list(zipped) [(1, 'a = [1, 2, 3, 4]\n'), (2, 'for x in a:\n'), (3, '\tprint(x)\n'), (4, '\tprint(x*2)\n')]
We could have used a list for x, but in this case, it’s easier to use a range. All of our examples so far have involved two iterable sequences in the zip object, but there’s no reason we couldn’t have more:
>>> x = [1, 2, 3] >>> y = [4, 5, 6] >>> z = [7, 8, 9] >>> zipped = zip(x,y,z) >>> list(zipped) [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
Note that in earlier versions of Python (2.X), typing in the name of the zip object at the interactive prompt will return the contents of the zip object. This is because in Python 2.X, the zip object is a list. In Python 3.0, you need to convert the zip object into a list first. This means a little extra coding, but it is also an asset in larger programs. Delayed evaluation conserves memory and avoids pauses while large result lists are computed.
The Range Function
We demonstrated here that the range is also an iterator; in 3.0, it returns an iterator that generates numbers in the range on demand, instead of building the result list in memory. This subsumes the older 2.X xrange, and you must use list(range()) to force an actual range if one is needed. For example:
>>> myrange = range(10) >>> myrange range(0, 10) >>> I = iter(myrange) >>> next(I) 0 >>> next(I) 1 >>> next(I) 2 >>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Unlike the list returned by such a call in 2.X, range objects in 3.0 support only iteration, indexing, and the len function. They do not support any other sequence operations. Thus, you should use list if you need more list tools.
>>> myrange = range(10) >>> len(myrange) 10 >>> myrange[0] 0 >>> myrange[-1] 9 >>> next(I) 3 >>> I.__next__() 4
It should also be noted that Python 2.X has a built-in object called xrange, which is like range but produces items on demand instead of building a list of results in memory all at once. Since the iterator-based range does this in Python 3.0, xrange is no longer available and has been subsumed. You may still see it, however, in older Python code.
External Links:
Zip objects at doc.python.org
Python Iterators at Python Wiki
Python Iterator tutorial at bogotobogo.com
Recent Comments