2

I have read about yield at What does the "yield" keyword do in Python? keyword in python but i have one question that how system identity that yield iterated once.

def test_yield():
    name = 'Hello World!'
    for i in name:
        yield i

y= test_yield()

print "first yield",y
for c in y:
    print c

print "second yield",y
for c in y:
    print c  

Output

first yield <generator object test_yield at 0x7f4c2bc10be0>
H
e
l
l
o

W
o
r
l
d
!
second yield <generator object test_yield at 0x7f4c2bc10be0>

In output second time yield object printed but not iterate.so how program identity that its executed once?

Alpesh Valaki
  • 1,611
  • 1
  • 16
  • 36
  • you are just printing out the generator object with this. `print "second yield",y` – e4c5 Jun 06 '17 at 07:37
  • i have also sendcond time loop for c in y: print c – Alpesh Valaki Jun 06 '17 at 07:39
  • It's not clear what you expect to happen in this case. Every generator is an iterator. You exhaust the iterator once and once that's happened, there's nothing further to iterate. – pvg Jun 06 '17 at 07:42
  • A `yield` statement stops the execution of the generator and yields a value. After the first for loop you have exhausted the generator (it has exited its inner `for` loop and stopped execution). The second `for` loop therefore has no more values to retrieve. – Kendas Jun 06 '17 at 07:43

4 Answers4

2

Looping through an iterator "uses it up". So your first yield loop iterates through it and reaches the end. Just as if you opened a file and read all of the lines until EOF. After that, no matter how many times you call read(), you won't get more data, only EOF. Similarly, once your iterator has reached its last element, calling .next on it just raises StopIteration.

BoarGules
  • 16,440
  • 2
  • 27
  • 44
  • +1 for mentioning `StopIteration`. I would just add a few words about the fact that iterators are objects with certain state that allows us loop through them. – gonczor Jun 06 '17 at 07:46
  • @gonczor the result would be exactly the same with or without the implementation detail of `StopIteration` – pvg Jun 06 '17 at 08:50
2

When a generator function calls yield, the "state" of the generator function is frozen; the values of all variables are saved and the next line of code to be executed is recorded until next() is called again. Once it is, the generator function simply resumes where it left off. If next() is never called again, the state recorded during the yield call is (eventually) discarded.

Given that when the generator function reaches it's end, a StopIteration Exception is raised, making it exhausted hence you have to reload it, that is the reason it didn't iterate any values during the second call.

Note : for gets values by calling next() implicitly

Kishy Nivas
  • 663
  • 8
  • 21
1

The first time the for calls the generator object created from your function, it will run the code in your function from the beginning until it hits yield, then it’ll return the first value of the loop. Then, each other call will run the loop you have written in the function one more time, and return the next value, until there is no value to return. In your second for loop, there's no more value to retrieve because you already wasted them.

For more insight as to what's happening behind the scenes, the for loop can be rewritten to this:

iterator = some_func()
try:
    while 1:
        print iterator.next()
except StopIteration:
    pass
1

When you wrote y = test_yield() you initialize iterator and when you finish your iteration after first for c in y: the iterator was ended. You need to initialize once more like:

def test_yield():
      name = 'Hello World!'
      for i in name:
        yield i

y= test_yield()

print "first yield",y
for c in y:
    print c

# once again
y= test_yield()  

print "second yield",y
for c in y:
    print c  
Artem Kryvonis
  • 128
  • 2
  • 13