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?
-
2I don't know. I am trying it out because I haven't found any examples. That's why I am asking here, obviously.blueFast– blueFast2015年10月09日 10:31:47 +00:00Commented Oct 9, 2015 at 10:31
3 Answers 3
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.
2 Comments
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
5 Comments
return4(). at the point where yield from is executed this has already evalutated to 4.def range4(): return range(4) you could then use yield from range4() even though range4 is not a generator.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.