When I create a class based generator, why do I have to call the next? [duplicate]

When I create a class based generator, why do I have to call the next? [duplicate]



This question already has an answer here:



I'm new to Python and I'm reading the book Python Tricks. In the chapter about generators, it gives the following example (with some changes)


class BoundedGenerator:
def __init__(self, value, max_times):
self.value = value
self.max_times = max_times
self.count = 0

def __iter__(self):
return self

def __next__(self):
if self.count < self.max_times:
self.count += 1
yield self.value



After that, I write a loop, instantiate the generator and print the value:


for x in BoundedGenerator('Hello world', 4):
print(next(x))



Why do I have to call the next(X) inside the loop?


next(X)



I (think) I understand that the __iter__ function will be called in the loop line definition and the __next__ will be called in each iteration, but I don't understand why I have to call the next again inside the loop. Is this not redundant?
If I don't call the __next__ function, my loop will run forever.


__iter__


__next__


__next__



This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.






This is not jow you use generators, generators exist to allow you to write iterators without the class-overhead. So, a generator function makes a great __iter__ method for a iterable (or any method you want to return an iterator from), but it doesn't make sense as the __next__ method of an iterator class, unless you want your iterator to return other iterators.

– juanpa.arrivillaga
Sep 8 '18 at 18:53



__iter__


__next__






Quite frankly, this is a terrible and confusing example if it comes from that book, it muddies the water on generators, iterators, and iterable (three distinct albeit related concepts)

– juanpa.arrivillaga
Sep 8 '18 at 18:57






Hi, thanks for the explanation and your time. Just to try to show the author's point, he starts with this kind of example but goes along and uses generator functions and generator expression and he gives the same opinion that I could achieve the same without this boilerplate code using one of the two other options (expressions or functions).

– Thiago
Sep 9 '18 at 14:26





1 Answer
1



Your __next__ method itself is a generator function due to using yield. It must be a regular function that uses return instead.


__next__


yield


return


def __next__(self):
if self.count < self.max_times:
self.count += 1
return self.value # return to provide one value on call
raise StopIteration # raise to end iteration



When iterating, python calls iter.__next__ to receive the new value. If this is a generator function, the call merely returns a generator. This is the same behaviour as for any other generator function:


iter.__next__


>>> def foo():
... yield 1
...
>>> foo()
<generator object foo at 0x106134ca8>



This requires you to call next on the generator to actually get a value. Similarly, since you defined BoundedGenerator.__next__ as a generator function, each iteration step provides only a new generator.


next


BoundedGenerator.__next__



Using return instead of yield indeed returns the value, not a generator yielding said value. Additionally, you should raise StopIteration when done - this signals the end of the iteration.


return


yield


raise StopIteration






Thank you for your time and explanation. That makes sense to me know.

– Thiago
Sep 9 '18 at 14:33

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

How do I collapse sections of code in Visual Studio Code for Windows?

ャフサォクコ ケウ,コ,ワ メ,ロスョノ゙,クネ,フムカヤヲニ,エコ゚ツ ウイオン゙ケワサネォキモュキォウイノンコチ゚メヌナイゥフュ,カヒウネェ ネ,ホノケ,ムュキ ッボーミュハ,チ ツス ィ メウイマヤ,゙ウチ ヅ ロ,ォジヌェ ャヌット ェ,マャ,チナエヒネソキツテ トホヲヲミーァ