Although the process of creating a Python iterator is powerful, it is often inconvenient to use. The generator is a simple way to complete the iteration.
1. Two ways to implement generator
The generator in Python saves the algorithm, and only when the value needs to be calculated does it go down to calculate the value. It is a lazy evaluation.
There are two ways to create a generator.
The first method: change the [] of a list generator to () to create a generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10)) # Note that after changing [] to (), instead of generating a tuple, it generates a generator
>>> g
<generator object <genexpr> at 0x1022ef630>
The second way: using the yield keyword in the function, the function becomes a generator.
When there is a yield in the function, the execution will stop until the yield is reached, and it will be counted down when it is necessary to count down. So even if the generator function has an infinite loop, it does not matter, it will count as much as it needs to count, and it will not count down if it does not.
def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
f = fib()
print f, next(f), next(f), next(f)
# <generator object fib at 0x7f89769d1fa0> 0 1 1
As in the above example, the f is output for the first time, it is a generator, and every time it is next, it executes to yield a.
Of course, next() is rarely used. We can use a for loop to traverse a generator. In fact, the internal implementation of a for loop is to call next().
The generator can avoid unnecessary calculations and bring performance improvements; and it will save space and can realize infinite loop (infinite) data structures.
2. The concept of Iterable and Iterator
The objects that can directly act on the for loop are collectively called iterable objects: Iterable.
Including collection data types (list, tuple, dict, set, str, etc.) and generators (generator).
You can use isinstance() to determine whether an object is an Iterable object.
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
Iterator: Iterator.
It represents a data stream. The Iterator object can be called by the next() function and keep returning the next data until a StopIteration error is thrown when there is no data. You can think of this data stream as an ordered sequence, but we can't know the length of the sequence in advance, and can only continue to calculate the next data on demand through the next() function, so Iterator's calculation is lazy, only when needed It will be calculated when the next data is returned. Iterator can even represent an infinite data stream, such as all natural numbers. Using list is never possible to store all natural numbers.
Generators are all Iterator objects, but list, dict, str are Iterable, but not Iterator.
Iterable list, dict, str and other Iterable can be used iter () function:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
Python's for loop is essentially realized by continuously calling the next() function, for example:
for x in [1, 2, 3, 4, 5]:
pass
Is actually equivalent to:
# First obtain the Iterator object:
it = iter([1, 2, 3, 4, 5])
# Loop:
while True:
try:
# Get the next value:
x = next(it)
except StopIteration:
# Exit Stop Loop when it encounters StopIteration
break
3.itertools module
Python's built-in module itertools provides functions for operating iteration objects, which is very convenient and practical. for instance:
islice(iterable, [start,] stop [, step]):
Create an iterator that generates items in a manner similar to the slice return value: iterable[start: stop: step], will skip the first start items, iteration stops at the position specified by stop, step specifies the step used to skip items Breadth. Unlike slices, negative values will not be used for any start, stop, and step. If start is omitted, the iteration will start at 0. If step is omitted, the step size will be 1.
from itertools import islice
def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
f = fib()
print list(islice(f, 10))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]