Why does `yield from 'in a generator expression give` None`?

I have the following code:

import itertools for c in ((yield from bin(n)[2:]) for n in range(10)): print(c) 

Output:

  0 None 1 None 1 0 None 1 1 None 

... etc. Why does None appear? If I instead:

 def hmm(): for n in range(10): yield from bin(n)[2:] for c in hmm(): print(c) 

Then I get what I expect:

 0 1 1 0 1 1 

... etc. Also, is there a way to write it as a generator expression to get the same result as the last?

+4
python generator yield generator-expression
source share
1 answer

yield is an expression, and its value is everything that is sent to the generator with send . If nothing is sent, yield is None. In your yield from example, the values ​​from the list are displayed, but the value of the yield from expression itself is None, which is given at each iteration of the covering generator expression (i.e., each value is range(10) ).

Your example is equivalent:

 def hmm(): for n in range(10): yield (yield from bin(n)[2:]) for item in hmm(): print(item) 

Pay attention to the extra yield .

You will always have this problem if you try to use yield in the generator expression, because the generator expression already gives its target values, so if you add an explicit yield , you add an additional expression ( yield ), the value of which will also be displayed in the generator . In other words, something like (x for x in range(5)) already gives numbers in range(5) ; if you do something like ((yield x) for x in range(5)) , you get the values ​​of the yield expression in addition to the numbers.

As far as I know, there is no way to get simple yield from behavior (without extra Nones) using generator understanding. For your case, I think you can achieve what you want using itertools.chain.from_iterable :

 for c in itertools.chain.from_iterable(bin(n)[2:] for n in range(10)): print(c) 

(Edit: I realized that you can get yield from behavior in the understanding of the generator using nested for : x for n in range(10) for x in bin(n)[2:] sentences. However, I don’t think it is more readable than using itertools.chain .)

+10
source share

All Articles