I have the following code:
import itertools
for c in ((yield from bin(n)[2:]) for n in range(10)):
print(c)
The output is:
0
None
1
None
1
0
None
1
1
None
... etc. Why do the Nones appear? If I instead have:
def hmm():
for n in range(10):
yield from bin(n)[2:]
for c in hmm():
print(c)
Then I get what I would expect:
0
1
1
0
1
1
... etc. Further, is there a way to write it as the generator expression to get the same result as the latter?
yieldis an expression, and its value is whatever is sent into the generator withsend. If nothing is sent in, the value ofyieldis None. In your exampleyield fromyields the values from the list, but the value of theyield fromexpression itself is None, which is yielded at each iteration of the enclosing generator expression (i.e., every value ofrange(10)).Your example is equivalent to:
Note the extra
yield.You will always have this issue if you try to use
yieldin a generator expression, because the generator expression already yields its target values, so if you add an explicityield, you are adding an extra expression (theyieldexpression) whose value will also be output in the generator. In other words, something like(x for x in range(5))already yields the numbers inrange(5); if you do something like((yield x) for x in range(5)), you're going to get the values of theyieldexpression in addition to the numbers.As far as I know, there is no way to get the simple
yield frombehavior (without extra Nones) using a generator comprehension. For your case, I think you can achieve what you want by usingitertools.chain.from_iterable:(Edit: I realized you can get the
yield frombehavior in a generator comprehension by using nestedforclauses:x for n in range(10) for x in bin(n)[2:]. However, I don't think this is any more readable than usingitertools.chain.)