As a contrived example:
myset = set(['a', 'b', 'c', 'd'])
mydict = {item: (yield ''.join([item, 's'])) for item in myset}
and list(mydict)
gives:
['as', 'cs', 'bs', 'ds', {'a': None, 'b': None, 'c': None, 'd': None}]
What happens here? What does yield
do? And is this behavior consistent no matter what expression follows yield
?
Note: I know that doing mydict = {item: ''.join([item, 's']) for item in myset}
would give the dictionary {'a': 'as', 'b': 'bs', 'c': 'cs', 'd': 'ds'}
, which seems to be what I am trying to do here.
First of all, what does yield
return? The answer in this case is None
, because yield
returns the parameter passed to next()
, which is nothing in this case (list
doesn't pass anything to next
).
Now here's your answer:
>>> myset = set(['a', 'b', 'c', 'd'])
>>> mydict = {item: (yield ''.join([item, 's'])) for item in myset}
>>> mydict
<generator object <dictcomp> at 0x0222BB20>
The dict comprehension is turned into a generator, because you used yield
in a function body context! This means that the whole thing isn't evaluated until it's passed into list
.
So here's what happens:
list
calls next(mydict)
.''.join([item, 's'])
to list
and freezes the comprehension.list
calls next(mydict)
.yield
(None
) to item
in the dictionary and starts a new comprehension iteration.And at last the actual generator object returns the temporary in the body, which was the dict
. Why this happens is unknown to me, and it's probably not documented behaviour either.