Освоение yield в Python: генератор против return — практическое руководство
Что такое yield в Python?
Ключевое слово yield ведёт себя как return, но вместо немедленного возврата значения оно возвращает объект-генератор, по которому можно итерироваться. Когда вызывается функция, содержащая yield, выполнение приостанавливается на первом операторе yield и передаёт управление вызывающему коду с генератором. Последующие вызовы next() или цикл for возобновляют выполнение с этой точки, выдавая следующее значение.
Ключевые выводы
- Yield создаёт генератор, позволяя ленивую оценку.
- Генераторы эффективны по памяти для больших или бесконечных последовательностей.
- Чтение из генератора возможно через
for-in,list()илиnext(). - После исчерпания генератор нельзя повторно использовать; нужно вызвать функцию снова.
Синтаксис
yield expression
Практический пример: простой yield
def test_yield():
yield "Welcome to Guru99 Python Tutorials"
output = test_yield()
print(output)
Вывод:
<generator object test_yield at 0x00000028265EB9A8>
Объект-генератор содержит yielded-значение. Для доступа к нему итерируйте:
for value in output:
print(value)
Вывод:
Welcome to Guru99 Python Tutorials
Генераторы объяснены
Функция-генератор — особая функция, возвращающая итерируемый объект-генератор. В отличие от обычных функций, возвращающих единственное значение, генератор выдаёт последовательность значений лениво, производя каждое только по запросу.
Создание функции-генератора
def generator_example():
yield "H"
yield "E"
yield "L"
yield "L"
yield "O"
for letter in generator_example():
print(letter)
Вывод:
H E L L O
Обычная функция против функции-генератора
Рассмотрим пару функций:
# Обычная функция
def normal_test():
return "Hello World"
# Функция-генератор
def generator_test():
yield "Hello World"
print(normal_test()) # → Hello World
print(generator_test()) # → <generator object generator_test>
Обычные функции завершаются на return; генераторы приостанавливаются на yield, возвращая управление вызывающему коду с объектом-генератором.
Потребление генератора
Значения из генератора можно извлекать с помощью:
- циклов
for-in list()для материализации всех значенийnext()для ручного пошагового извлечения
Пример: чётные числа
def even_numbers(n):
for x in range(n):
if x % 2 == 0:
yield x
print(list(even_numbers(10))) # → [0, 2, 4, 6, 8]
Использование for-in
for num in even_numbers(10):
print(num)
Вывод:
0 2 4 6 8
Использование next()
gen = even_numbers(10)
for _ in range(6):
try:
print(next(gen))
except StopIteration:
print("End of generator")
Вывод:
0 2 4 6 8 End of generator
Генераторы — одноразовые
После полной итерации генератор исчерпывается. Повторная итерация ничего не даёт, если не вызвать функцию-генератор снова.
gen = even_numbers(10)
for num in gen:
print(num)
print(list(gen)) # → []
Yield в действии: ряд Фибоначчи
def fibonacci_series(limit):
a, b = 0, 1
count = 0
while count < limit:
yield a
a, b = b, a + b
count += 1
fib = fibonacci_series(7)
for num in fib:
print(num)
Вывод:
0 1 1 2 3 5 8
Вызов функции с yield
Ниже мы возводим числа в квадрат с помощью вспомогательной функции и генератора, выдающего каждый результат.
def square(n):
return n * n
def square_range(n):
for i in range(n):
yield square(i)
for value in square_range(10):
print(value)
Вывод:
0 1 4 9 16 25 36 49 64 81
Когда использовать yield вместо return
- Обработка больших или потоковых данных, где загрузка всех элементов сразу непрактична.
- Генерация потенциально бесконечных последовательностей (например, ленивые читатели файлов).
- Улучшение памяти и времени запуска для больших наборов данных.
- Когда нужно приостанавливать и возобновлять вычисления, а не просто возвращать конечное значение.
Yield vs Return — краткая справка
| Yield | Return |
|---|---|
| Возвращает генератор; выполнение возобновляется при итерации. | Завершает функцию; возвращает единственное значение немедленно. |
Приостанавливается на каждом yield, экономя память. | Выделяет память для возвращаемого значения. |
| Идеален для больших или бесконечных последовательностей. | Подходит для небольших, дискретных результатов. |
| Время выполнения быстрее для больших наборов данных. | Может накладывать накладные расходы при обработке огромных данных. |
Ключевые выводы
- Yield производит объект-генератор, а не значение.
- Генераторы выдают значения лениво, держа использование памяти минимальным.
- Читайте значения через
for-in,list()илиnext(). - После исчерпания генераторы нужно пересоздать для повторного использования.
- Yield превосходит return для больших или потоковых данных.
Python
- Lambda-функции в Python: практическое руководство по анонимным функциям
- Генераторы в Python: эффективная итерация и продвинутые сценарии
- Замыкания в Python: как вложенные функции захватывают переменные
- Декораторы в Python: улучшайте функции экспертными техниками
- Мастерство метода strip() в Python: подробное руководство и практические примеры
- Python len(): практическое руководство по измерению длины объектов
- Освоение лямбда-функций Python: практические примеры и лучшие практики
- Функция round() в Python: подробное объяснение с практическими примерами
- Освоение функции map() в Python: синтаксис, примеры и лучшие практики
- Counter в collections Python: эффективное подсчёт, обновление и арифметические операции