Использование урожая с пониманием dict

Как надуманный пример:

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

и list(mydict) дает:

['as', 'cs', 'bs', 'ds', {'a': None, 'b': None, 'c': None, 'd': None}]

Что здесь происходит? Что делает yield? И соответствует ли это поведение независимо от того, какое выражение следует за yield?

Примечание. Я знаю, что выполнение mydict = {item: ''.join([item, 's']) for item in myset} даст словарь {'a': 'as', 'b': 'bs', 'c': 'cs', 'd': 'ds'}, который, кажется, я пытаюсь сделать здесь.

Ответ 1

Прежде всего, что возвращает yield? Ответ в этом случае None, потому что yield возвращает параметр, переданный в next(), который в этом случае ничего нет (list ничего не передает next).

Теперь вот ваш ответ:

>>> myset = set(['a', 'b', 'c', 'd'])
>>> mydict = {item: (yield ''.join([item, 's'])) for item in myset}
>>> mydict
<generator object <dictcomp> at 0x0222BB20>

Понимание dict превращается в генератор, потому что вы использовали yield в контексте тела функции! Это означает, что все это не оценивается до тех пор, пока оно не перейдет в list.

Итак, что происходит:

  • list вызывает next(mydict).
  • Доходность возвращает ''.join([item, 's']) до list и замораживает понимание.
  • list вызывает next(mydict).
  • Понимание возобновляется и присваивает результат yield (None) в item в словаре и запускает новую итерацию понимания.
  • Вернитесь к 1.

И наконец, фактический объект-генератор возвращает временное тело, которое было dict. Почему это происходит, мне неизвестно, и это, вероятно, также не документированное поведение.

Ответ 2

Я думаю, что yield превращает ваше замечательное понимание слова в выражение генератора. Итак, когда вы выполняете итерацию по генератору, yield "уступает" элементам, которые выглядят as, bs..., но оператор yield ... возвращает None. Итак, в конце дня вы получаете словарь, похожий на {'a': None, 'b': None, ...}.

Часть, которая меня смущает, - это то, почему словарь действительно уступает в конце. Я предполагаю, что это поведение на самом деле не совсем определено стандартом, но я мог ошибаться в этом.

Интересно, если вы попробуете это с пониманием списка, питон жалуется:

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

Но он Хорошо в генераторе (видимо).

Ответ 3

Я нахожу! ^ _ ^

В нормальной жизни выражение

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

оцените следующее:

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

print d(myset).next()

Почему yield result вместо return result? Я думаю, что необходимо поддерживать вложенные списки * следующим образом:

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

Итак, будет выглядеть как этот код?

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

и

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

Сначала будут возвращены все значения ''.join([item, 's']), и последний будет возвращен dict result. Значение выражения yield None, поэтому значения в result тоже None.

* Более правильная интерпретация оценки вложенных списков:

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

Ответ 4

Я думаю, что ваш код должен выполнить сходство этого:

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

d(myset)

Сначала оцениваем yield ''.join([item, 's'] (и возвращаем 'as', 'cs' и т.д.). Значение выражения yield равно None, потому что отправляется обратно генератору. И затем eval yield item, None, который возвращает кортежи ('a', None), ('b', None).

Итак, у меня есть:

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

Что будет дальше, я не понимаю.