Страницы

Поиск по вопросам

четверг, 2 января 2020 г.

Генератор yield

#python #yield


Пример из изучаемой мною книжки

def fibonacci_generator():
    a = b = 1
    while True:
        yield a 
        a, b = b, a + b
        print(a, b) #поможет лучше понять работу
fib = fibonacci_generator()

for i in fib:
    if i > 100:
        break
    else:
        print('Generated:', i)


Что в данном коде выполняет функция yield? В книге написано - "Она [генераторная
инструкция], начинается с ключевого слова yield и определяет объект-генератор (то есть
переменную a?), который возвращается оператору (print?), вызвавшему функцию. Когда
генераторная инструкция исполняется, состояние объекта генератора "замораживается"
и сохраняется. Объект, возвращаемый генераторной инструкцией, может быть присвоен переменной
(это мы сделали на 7 строке кода?)."
Но я так и не понял, как это отражается в результате кода?

Я пытаюсь понять работу кода сопоставив код с результатом его выполнения. Вот несколько
строк результата:

Generated: 1
1 2
Generated: 1
2 3
Generated: 2
3 5
Generated: 3
5 8
Generated: 5
8 13
...


Что после операций a, b = b, a + b становится содержимым функции fibonacci_generator?
Результат суммы a и b? Переменная а на второй итерации равна 2, потому что "при этом
она сохраняет состояние своего последнего вызова и при следующем вызове продолжает
работу с той же точки."? Почему, к примеру, на первой итерации, вывод переменной b
отображает 2, ведь сумма а +  b просто какое-то, ничему не присвоенное выражение?
    


Ответы

Ответ 1



yield определяет объект-генератор (то есть переменную a?) Нет, под объектом генератором подразумевается вся функция целиком. Она преобразуется в генератор, если в её теле присутствует инструкция yield. Переменная a — это то, что будет генерироваться и возвращаться. который возвращается оператору (print?) Нет, генератор в Вашем коде возвращается и присваивается переменной fib: fib = fibonacci_generator() print(type(fib)) # Объект, возвращаемый генераторной инструкцией, может быть присвоен переменной (это мы сделали на 7 строке кода?) Нет, в 7 строке кода Вы возвращаете новое сгенерированное значение и замораживаете генератор, а присваивание этого значения переменной неявно происходит в 9 строке кода: for i in fib: ... Инструкция for на каждой итерации будет присваивать i какое-то значение. Для этого она будет обращаться к функции (через методы итерирования). Вы вручную можете получать новые значения из генератора, используя функцию next: i = next(fib) Попробуйте отказаться от цикла for и использовать только инструкцию выше, чтобы лучше понять, как генератор возвращает новое значение. a, b = b, a + b Это сокращённая запись кортежного присваивания: (a, b) = (b, a + b) Элементы из левого кортежа будут сопоставлены с элементами из правого (количество должно быть одинаково) и им будут присвоены соответствующие значения.

Ответ 2



a, b = c, d это почти то же самое, что a = c b = d только вычисляется не последовательно, а справа налево. Чтобы поменять местами два значения можно написать a, b = b, a У тебя почти то же самое, но вместо второй переменной сумма: a, b = b, a + b

Ответ 3



Генераторы это очень интересная штука. https://docs.python.org/3/reference/expressions.html#generator-expressions Вот документация. Простым языком: yield - это выражение, которое используется при создании функции-генераторы или асинхронного генератора. Еще проще: генератор - это конструкция, в которой реализован протокол итератора, т.е. любой генератор = итерируемая последовательность, которую можно перебирать в цикле, как списки, только значения она возвращает вызовом метода next(), значит - не сразу, а последовательно, за каждое обращение.

Комментариев нет:

Отправить комментарий