Use of yield with a dict comprehension

前端 未结 4 843
醉梦人生
醉梦人生 2021-02-07 01:53

As a contrived example:

myset = set([\'a\', \'b\', \'c\', \'d\'])
mydict = {item: (yield \'\'.join([item, \'s\'])) for item in myset}

and

相关标签:
4条回答
  • 2021-02-07 02:23

    I think that your code has to execute similarity of this:

    def d(myset):
        for item in myset:
            yield item, (yield ''.join([item, 's']))
    
    d(myset)
    

    Firstly, evaluated yield ''.join([item, 's'] (and return 'as', 'cs', etc.). Value of yield expression is None, because is sent back to the generator. And then eval yield item, None, that return tuples ('a', None), ('b', None).

    So, I have:

    >>> list(d(myset))
    ['as', ('a', None), 'cs', ('c', None), 'bs', ('b', None), 'ds', ('d', None)]
    

    What happens next, I do not understand.

    0 讨论(0)
  • 2021-02-07 02:34

    I think that yield is turning your nice dictionary comprehension into a generator expression. So, when you're iterating over the generator, yield is "yielding" the elements that look as, bs ..., but the statement yield ... returns None. So, at the end of the day, you get a dictionary looking like {'a': None, 'b': None, ...}.

    The part that confuses me is why the dictionary is actually yielded at the end. I'm guessing that this behavior is actually not well defined by the standard, but I could be wrong about that.

    Interestingly enough, if you try this with a list comprehension, python complains:

    >>> a = [(yield i) for i in myset]
      File "<stdin>", line 1
    SyntaxError: 'yield' outside function
    

    But it's Ok in a generator (apparently).

    0 讨论(0)
  • 2021-02-07 02:35

    I find! ^_^

    In normal life, expression

    print {item: (yield ''.join([item, 's'])) for item in myset} 
    

    evaluate like this:

    def d(myset):
        result = {}
        for item in myset:
            result[item] = (''.join([item, 's']))
        yield result
    
    print d(myset).next()
    

    Why yield result instead return result? I think it is necessary to support nested list comprehensions* like this:

    print {i: f.lower() for i in nums for f in fruit}  # yes, it's works
    

    So, would look like this code?

    def d(myset):
        result = {}
        for item in myset:
            result[item] = (yield ''.join([item, 's']))
        yield result
    

    and

    >>> print list(d(myset))
    ['as', 'cs', 'bs', 'ds', {'a': None, 'b': None, 'c': None, 'd': None}]
    

    First will be returned all values of ''.join([item, 's']) and the last will be returned dict result. Value of yield expression is None, so values in the result is None too.

    * More correct interpretation of evaluate nested list comprehensions:

    print {i: f.lower() for i in nums for f in fruit}
    
    # eval like this:
    
    result = {}
    for i, f in product(nums, fruit): # product from itertools
        key, value = (i, f.lower())
        result[key] = value
    print result
    
    0 讨论(0)
  • 2021-02-07 02:44

    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:

    1. list calls next(mydict).
    2. Yield returns ''.join([item, 's']) to list and freezes the comprehension.
    3. list calls next(mydict).
    4. The comprehension resumes and assigns the result of yield (None) to item in the dictionary and starts a new comprehension iteration.
    5. Go back to 1.

    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.

    0 讨论(0)
提交回复
热议问题