预计阅读本页时间:-
Generators Are Single-Iterator Objects
Both generator functions and generator expressions are their own iterators and thus support just one active iteration—unlike some built-in types, you can’t have multiple iterators of either positioned at different locations in the set of results. For example, using the prior section’s generator expression, a generator’s iterator is the generator itself (in fact, calling iter on a generator is a no-op):
>>> G = (c * 4 for c in 'SPAM')
>>> iter(G) is G # My iterator is myself: G has __next__
True
广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元
If you iterate over the results stream manually with multiple iterators, they will all point to the same position:
>>> G = (c * 4 for c in 'SPAM') # Make a new generator
>>> I1 = iter(G) # Iterate manually
>>> next(I1)
'SSSS'
>>> next(I1)
'PPPP'
>>> I2 = iter(G) # Second iterator at same position!
>>> next(I2)
'AAAA'
Moreover, once any iteration runs to completion, all are exhausted—we have to make a new generator to start again:
>>> list(I1) # Collect the rest of I1's items
['MMMM']
>>> next(I2) # Other iterators exhausted too
StopIteration
>>> I3 = iter(G) # Ditto for new iterators
>>> next(I3)
StopIteration
>>> I3 = iter(c * 4 for c in 'SPAM') # New generator to start over
>>> next(I3)
'SSSS'
The same holds true for generator functions—the following def statement-based equivalent supports just one active iterator and is exhausted after one pass:
>>> def timesfour(S):
... for c in S:
... yield c * 4
...
>>> G = timesfour('spam') # Generator functions work the same way
>>> iter(G) is G
True
>>> I1, I2 = iter(G), iter(G)
>>> next(I1)
'ssss'
>>> next(I1)
'pppp'
>>> next(I2) # I2 at same position as I1
'aaaa'
This is different from the behavior of some built-in types, which support multiple iterators and passes and reflect their in-place changes in active iterators:
>>> L = [1, 2, 3, 4]
>>> I1, I2 = iter(L), iter(L)
>>> next(I1)
1
>>> next(I1)
2
>>> next(I2) # Lists support multiple iterators
1
>>> del L[2:] # Changes reflected in iterators
>>> next(I1)
StopIteration
When we begin coding class-based iterators in Part VI, we’ll see that it’s up to us to decide how any iterations we wish to support for our objects, if any.