简体   繁体   中英

Diff between “return” and “yield” stmts in generators

Have a look at the code:

def main():
    for p in test1(): print(p)

def test1():
    s = set()
    s.update(range(5))
    for p in s: yield p
    return s

Why I got only 0,1,2,3,4? The output should be: 0,1,2,3,4 two times (1 for 'yield' and 1 for 'return')

PS: Python-3.4

A return statement in a Python 3.3+ generator doesn't do what you think it does. The value is not returned to the caller like in a normal function, but added as an attribute on the StopIteration exception the generator raises to signal that it is done iterating. The behavior you're seeing in your loop is unrelated.

First, lets understand the loop behavior. This comes down to a simple fact: The loop variable (eg i ) doesn't go out of scope when a for loop ends:

for i in range(5): # this loop will print 0 through 4
    print(i)

print(i) # this line will print 4 again, since 4 it was the last value assigned to i

Your code is doing exactly this. The else clause you're using does nothing special, since you never break out of the loop. (Neftas's answer explains what an else attached to a loop is for.)

As for where the return value is going, you can find it if you iterate over your generator manually:

gen = test1()
print(next(gen)) # prints 0
print(next(gen)) # prints 1
print(next(gen)) # prints 2
print(next(gen)) # prints 3
print(next(gen)) # prints 4
print(next(gen)) # prints set([0,1,2,3,4]) from the last yield statement
try:
    next(gen)
except StopIteration as e:
    print(e.value) # prints set([0,1,2,3,4]) from the return statement

This isn't a very common usage. The usual way of getting at the returned value is by using the result of a yield from expression in another generator:

def test3():
    print(yield from test1())

This is a generator that yields all the same values as test1 , but it also prints out the value that test1 returns.

I don't think the return idiom is terribly useful in most situations. yield from can be very useful in recursive or otherwise complex generators, but I've never found a need to return a value from one.

If you want more information about the yield from expression and the return value from generators, read PEP 380 , which describes the new features that were added in Python 3.3.

For a discussion of return in a generator, see Blckknght's answer, this is about the else clause in a for loop.

I read a nice article about else clauses in for loops if you don't like the documentation .

The gist of it is that an else clause in a for loop is all about completion, rather than about conditionals. Compare:

if 1:
    print "True"
else:
    print "False"

Here, the else clause is executed when the comparison falls through. But:

for i in xrange(5):
    if i == 123:
        print "Found it!"
        break
else:
    print "Value not in list"
# output: "Value not in list"

Here, the else clause gets executed unless the flow of execution hits the break statement:

for i in xrange(5):
    if i == 4:
        print "Found it!"
        break
else:
    print "Value not in list"
# output: "Found it!"

If your remove the break , both strings will be printed. In your code the flow of execution will always reach the else statement, so the code there is run.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM