I'm new to Python and I am finding the yield
statement quite useful. However, something surprised me. Putting multiple yield
statements in a function will result in each one being seen in a for var in fn()
loop. However, if I execute another function from the initial function that uses the yield
statement, that function is not executed. I had just taken the naive approach and just thought it would work.
E.g.
def fn2():
print("blah")
yield "you"
def fn():
yield "hi"
fn2()
yield "there"
for a in fn():
print('{}'.format(a))
If I were to comment out yield "you"
, my output would be:
hi
there
If not, it would be:
hi
blah
there
That there wasn't any warning or error of any sort and it just shrugged and continued to execute was even more surprising than it not working.
What's going on here?
CodePudding user response:
Functions with yield
are generators. They always produce an iterable, even if there is only a single yield
statement in them.
In order to get the value(s) the function produces, you must iterate.
You could use for v in fn2: yield v
, but Python also has a convenience statement: yield from
def fn2():
print("blah")
yield "you"
def fn():
yield "hi"
yield from fn2()
yield "there"
for a in fn():
print('{}'.format(a))
Python's generators are evaluated lazily. Creating one (in this case "calling fn2
") does not start the iteration. That's why it seems that fn2
isn't even called. It is called.
Imagine its return value as a bookmark right before the first line of the function body of fn2
. Once you actually start iterating, the "bookmark" will advance to the first yield
statement, and so on, until the function ends.