7

I haven't been able to find any examples of return values from the yield from expression. I have tried this simple code, without success:

def return4():
 return 4
def yield_from():
 res = yield from range(4)
 res = yield from return4()
def test_yield_from():
 for x in yield_from():
 print(x)
test_yield_from()

Which produces:

» python test.py 
0
1
2
3
Traceback (most recent call last):
 File "test.py", line 52, in <module>
 test_yield_from()
 File "test.py", line 48, in test_yield_from
 for x in yield_from():
 File "test.py", line 44, in yield_from
 res = yield from return4()
TypeError: 'int' object is not iterable

But I was expecting:

» python test.py 
0
1
2
3
4

Because, as stated in the PEP:

Furthermore, when the iterator is another generator, the subgenerator is allowed to execute a return statement with a value, and that value becomes the value of the yield from expression.

Obviously, I am not getting this explanation. How does a return in a "subgenerator" work with regards to yield from?

asked Oct 9, 2015 at 10:26
1
  • 2
    I don't know. I am trying it out because I haven't found any examples. That's why I am asking here, obviously. Commented Oct 9, 2015 at 10:31

3 Answers 3

14

Generators can return a value when they are exhausted:

def my_gen():
 yield 0
 return "done"
g = my_gen()
next(g)
next(g) # raises StopIteration: "done"

The returned value in a yield from statement will be this value. eg.

def yield_from():
 res = yield from my_gen()
 assert res == "done"

By default this value is None. That is res = yield from range(4) will set res as None.

answered Oct 9, 2015 at 10:42
Sign up to request clarification or add additional context in comments.

2 Comments

ok, that seems more clear. What is the use case for this? Would I use this to refactor a normal function into a subgenerator, for example?
Subgenerators and returning from a generator are used heavily in python's coroutine library. -- docs.python.org/3/library/asyncio-task.html . Here generators are used to create cooperative multithreading, rather to yield values.
2

yield from generator is short for

for i in generator:
 yield i

well it's a bit more commplicated than that: https://www.python.org/dev/peps/pep-0380/#formal-semantics .

this will not work well if generator = 4. (your return4() is not a generator. it's a function.)

in order to get what you wand you would just do this:

def yield_from():
 yield from range(4)
 yield 4
answered Oct 9, 2015 at 10:28

5 Comments

Sure. So, what do return statements in a subgenerator do? What is the meaning of: "the subgenerator is allowed to execute a return statement with a value, and that value becomes the value of the yield from expression"
you call your function: return4(). at the point where yield from is executed this has already evalutated to 4.
@jeckyll2hide if you had def range4(): return range(4) you could then use yield from range4() even though range4 is not a generator.
@Trengot ...that probably answers the question better than my attempt.
@Trengot: no, this is not what I am (and the PEP) talking about. I am talking about returning values from the subgenerator, not returning a generator.
1

I'm posting a working example for your tests.

return4 function is now a generator. To achieve that, a yield must be present anywhere in the function (there is a new related feature in Python 3.5, but that's not important now).

As you quoted already:

Furthermore, when the iterator is another generator, the subgenerator is allowed to execute a return statement with a value, and that value becomes the value of the yield from expression

Summary: you will get a value. You could print it, for example:

def yield_from():
 # ...
 val = yield from return4()
 print("value:", val) # prints value: 4

But you want to yield it, not print. Here is the complete code:

def return4():
 if False:
 yield None
 return 4
def yield_from():
 yield from range(4)
 yield (yield from return4())
def test_yield_from():
 for x in yield_from():
 print(x)
test_yield_from()
# prints numbers 0 to 4

You are probably asking yourself, what is it good for. There is almost no advantage when you are only receivng values from a generator. But yield from is a great feature when you are sending values to a generator. Try to find a good explanation of python coroutines. It's amazing.

answered Oct 9, 2015 at 15:10

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.