I am confused about why different looping constructs behave so differently when used with a simple generator. Consider the following code:
example_list = [1, 2, 3, 4, 5]
for_count = 0
next_count = 0
while_count = 0
def consumer(iterable):
for item in iterable:
yield
return
for item in consumer(example_list):
print("For Count: {0}".format(for_count))
for_count += 1
# First while loop
while consumer(example_list).next():
print("Next Count: {0}".format(next_count))
next_count += 1
# Second while loop
while consumer(example_list):
print("While Count: {0}".format(while_count))
while_count += 1
if while_count > 10: # add contrived limit for infinite loop
break
The output for this code is:
For Count: 0
For Count: 1
For Count: 2
For Count: 3
For Count: 4
While Count: 0
While Count: 1
While Count: 2
While Count: 3
While Count: 4
While Count: 5
While Count: 6
While Count: 7
While Count: 8
While Count: 9
While Count: 10
I would appreciate help understanding the following:
- How does the
for
loop know when to end but not the secondwhile
loop? I expected bothwhile
loops to exit immediately sinceNone
is yielded. - Why doesn't using
.next()
raise an exception? Theconsumer
routine isn't a class with a__next__()
method defined, so does it magically appear when you use theyield
keyword? - Why is it that if I change
consumer
toyield item
, the firstwhile
loop become infinite like the second one? - If I change
consumer
to simply return instead of yielding anything, the secondwhile
loop exits immediate instead of becoming infinite. I've been under the impression that ayield
is essentially areturn
that you can resume from. Why are they treated differently by awhile
loop?