_ = yield i
yield _
First it yield
s the value referenced by i
, e.g. 1
. Then it yields the value returned by the yield
operation, which is None
. It does this on each iteration of the loop.
for i in x:
_ = yield i
This simply yield
s the value referenced by i
, e.g. 1
, then proceeds to the next iteration of the loop, producing 2
, then 3
.
Unlike return
, the yield
keyword can be used in an expression:
x = return 0 # SyntaxError
x = yield 0 # perfectly fine
Now, when the interpreter sees a yield
, it will generate the indicated value. However, when it does so, that operation returns the value None
, just like mylist.append(0)
or print('hello')
will return
the value None
. When you assign that result to a reference like _
, you're saving that None
.
So, in the first snippet, you're yielding an object, then you save the "result" of that yield
operation, which is None
, and then you yield
that None
. In the second snippet, you yield an object, then you save the "result" of that yield
operation, but you never yield
that result, so None
does not appear in the output.
Note that yield
won't always return None
- this is just what you sent to the generator with send()
. Since that was nothing in this case, you get None
. See this answer for more on send()
.
yield
question, even if the question in question has nothing to do withyield
. This time, however, it is indeed related. – Penicillium