Why do function generators and class generators behave differently? I mean, with class generators I can use generator as many times as I want, but with function generators, I can only use it once? Why so?
def f_counter(low,high):
counter=low
while counter<=high:
yield counter
counter+=1
class CCounter(object):
def __init__(self, low, high):
self.low = low
self.high = high
def __iter__(self):
counter = self.low
while self.high >= counter:
yield counter
counter += 1
f_gen=f_counter(5,10)
for i in f_gen:
print(i,end=' ')
print('\n')
for j in f_gen:
print(j,end=' ') #no output
print('\n')
c_gen=CCounter(5,10)
for i in c_gen:
print(i,end=' ')
print('\n')
for j in c_gen:
print(j,end=' ')
Calling the f_gen()
function produces an iterator (specifically, a generator iterator ). Iterators can only ever be looped over once. Your class is not an iterator, it is instead an iterable , an object that can produce any number of iterators .
Your class produces a new generator iterator each time you use for
, because for
applies the iter()
function on the object you pass in, which in turn calls object.__iter__()
, which in your implementation returns a new generator iterator each time it is called.
In other words, you can make the class behave the same way by calling iter(instance)
or instance.__iter__()
before looping:
c_gen = CCounter(5,10)
c_gen_iterator = iter(c_gen)
for i in c_gen_iterator:
# ...
You can also make the CCounter()
into an iterator by returning self
from __iter__
, and adding an object.__next__()
method ( object.next()
in Python 2):
class CCounter(object):
def __init__(self, low, high):
self.low = low
self.high = high
def __iter__(self):
return self
def __next__(self):
result = self.low
if result >= self.high:
raise StopIteration()
self.low += 1
return result
Your class is an iterable, but not an iterator itself. Each time you call iter
on it, you get a new iterator.
If you want to replicate the behavior of the generator function with a class, then you want an iterator like this:
class CCounter(object):
def __init__(self, low, high):
self.low = low
self.high = high
self.counter = self.low
def __iter__(self):
return self
def __next__(self):
if self.counter > self.high:
raise StopIteration()
val = self.counter
self.counter += 1
return val
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.