0

Hi guys so I was wondering why when making the make_song() function it actually worked, I thought the version I'm going to show below would not work the way it did:

def make_song(count = 99, beverage = "soda"):
    while count > 0:
            if count > 1:
                yield "{} bottles of {} on the wall.".format(count, beverage)
                count -=1
            elif count == 1:
                yield "Only {} bottle of {} left!".format(count, beverage)
                count -= 1
                yield "No more {}!".format(beverage)

hey = make_song(5, "coke")
print(next(hey))
print(next(hey))
print(next(hey))
print(next(hey))
print(next(hey))
print(next(hey))

my conclusion was that when count == 1 it would print:

Only 1 bottle of coke left!

No more coke!

because they were both under the same if statement. To my surprise, it worked the way I wanted it to work, by printing only "Only 1 bottle of coke left!" when the count == 1, and then when i used next() again it would print "No more coke!", I didn't expect this one to work,

why did it not print both yields when count == 1 even though they were under the same if statement?

Community
  • 1
  • 1
  • `they were under the same if statement` has no meaning. Two yields, two results. – tkausl Apr 02 '20 at 15:55
  • `yield` stops the execution of the function, like return, just next time you call this function it continues from the point where it stopped. [what does the yield keyword do](https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do) – Alex Sveshnikov Apr 02 '20 at 15:56

3 Answers3

1

The way is

  • each yield gives a value to return
  • each call to next get the next value given by a yield

So as the 1 left and no more are given by a different yield you 2 next to get them

azro
  • 53,056
  • 7
  • 34
  • 70
1

The part of the code that determines when the generator gives you something is yield and not if. The if only determines which lines gets executed depending on a condition.

In practice a generator is a generalization of a function. A function returns a value once, while a generator returns as many times as a yield statement is reached. After each yield the execution is suspended, and upon the next call to next() the execution is resumed and continues until the next yield is found.

An alternative to the next() call is to use the iterator directly in a for loop, which will exhaust all possible yield endpoints.

For example:

for s in make_song(5, "coke"):
    print(s)

will give you:

5 bottles of coke on the wall.
4 bottles of coke on the wall.
3 bottles of coke on the wall.
2 bottles of coke on the wall.
Only 1 bottle of coke left!
No more coke!
norok2
  • 25,683
  • 4
  • 73
  • 99
0

The reason that it return "Only 1 bottle of coke left!" in the second to last, and "No more coke!" on the last next is that when you invoke next() in a method that yields the code on the method will run until there there is a yield.

Let's say that you are in the count == 2:

 while count > 0:
     if count > 1:
         yield "{} bottles of {} on the wall.".format(count, beverage)

code checks that count > 0 and continues to the next statement count > 1 since count == 2 it enters the if statement. The next line is the yield statement, which means it will return the string (and the line count -= 1 will not be executed until the next next()).

When next is invoked again the code will continue decreasing the counter to 1, and it leaves the if statement and goes back to the while statement. The while statement still holds True, the count > 1 now is False, therefore it goes to the elif statement which is True. The first statement is the yield that return yield "Only 1 bottle of coke left!. The following next() decrease the count and yields No more coke!