Ключевое слово yield
используется в функциях так же, как и ключевое слово return
— для возврата результата работы. Разница в том, что yield
возвращает генератор. Но чтоб им пользоваться грамотно, нам необходимо понять, как работают итераторы и генераторы.
Давайте рассмотрим пример итератора:
nums_list = [num ** 2 for num in range(5)]
for num in nums_list:
print(num)
print(nums_list, type(nums_list))
Результат:
>>> 0
>>> 1
>>> 4
>>> 9
>>> 16
>>> [0, 1, 4, 9, 16] <class 'list'>
Пояснение:
- Список
nums_list
– итерируемый объект. Итератор создается во время генерации списка с помощью list comprehension.
Любые объекты, для которых можно использовать цикл for, являются итерируемыми — списки, строки, множества, кортежи. Итерации очень удобны, потому что они не ограничивают количество повторных считываний данных. Однако вся информация находится в оперативной памяти, а при большом объеме данных это нежелательно.
Пример генератора:
nums_generator = (num ** 2 for num in range(5))
print(type(nums_generator))
for num in nums_generator:
print(num)
Результат:
>>> 0
>>> 1
>>> 4
>>> 9
>>> 16
>>> <generator object <genexpr> at 0x00000196EF719B60> <class 'generator'>
Пояснение:
- Генераторы также являются итерируемыми, но их можно прочитать только один раз. Генераторы не хранят значения в памяти, а создают их на лету:
Генераторы можно создать также с помощи list comprehension, отличием является, что мы используем круглые скобки () для объявления генератора, вместо квадратных [] у списка.
К генератору нельзя обратиться повторно, вычисляя каждый последующий элемент, генератор «забывает» предыдущий.
Рассмотрим применение yield:
# Создаем функцию для генератора
def create_generator():
nums_list = range(5)
for num in nums_list:
yield num ** 2
nums_generator = create_generator()
print(nums_generator)
for num in nums_generator:
print(num)
Результат:
>>> <generator object create_generator at 0x000001705CFB9B60>
>>> 0
>>> 1
>>> 4
>>> 9
>>> 16
Вместо return
стоит использовать yield
в тех случаях, когда функция возвращает большой объем данных, достаточный для однократного чтения.
Чтобы использовать его эффективно, вы должны понимать основную характеристику yield
: когда функция вызывается, код в теле функции не выполняется. Функция просто возвращает объект-генератор.
Код вызывается каждый раз, когда for обращается к генератору.
При первом запуске функции она будет исполняться, пока не дойдет до yield
, после чего вернет первое значение из цикла. При каждом последующем вызове будет происходить следующая итерация и будет возвращаться значение цикла. Процесс будет повторяться до тех пор, пока генератор не опустеет. Генератор считается пустым, если функция не встречает возврата — это происходит либо в конце цикла, либо при невыполнении условий if
и else
Ещё пример использования yield
# Программа на Python для генерации степеней 2
# от 2 до 256
def get_next_num():
n = 2
# Бесконечный цикл для генерации степеней 2
while True:
yield n
n *= 2 # При последующем обращении к
# get_next_num() выполнение
# продолжится отсюда
# Код для проверки get_next_num()
for num in get_next_num():
if num > 256:
break
print(num)
Результат:
>>> 2
>>> 4
>>> 8
>>> 16
>>> 32
>>> 64
>>> 128
>>> 256
Материал взят с proglib.io