Ответ
return завершает выполнение функции и возвращает одно значение. yield превращает функцию в генератор, который может возвращать последовательность значений по одному, сохраняя состояние между вызовами.
Ключевые отличия:
| Аспект | return |
yield |
|---|---|---|
| Возврат | Одно значение | Последовательность значений |
| Состояние | Функция завершается | Функция приостанавливается |
| Память | Все данные сразу | Ленивая загрузка |
| Тип | Любой объект | generator object |
Пример генератора с yield:
def read_large_file(file_path):
"""Чтение огромного файла построчно без загрузки в память"""
with open(file_path, 'r', encoding='utf-8') as f:
for line in f:
yield line.strip()
# Использование
for line in read_large_file('huge_data.txt'):
process_line(line) # Обрабатываем по одной строке
Когда использовать yield:
-
Работа с большими данными:
def batch_generator(data, batch_size=1000): """Разбивает данные на батчи""" for i in range(0, len(data), batch_size): yield data[i:i + batch_size] -
Бесконечные последовательности:
def fibonacci_generator(): """Генератор чисел Фибоначчи""" a, b = 0, 1 while True: yield a a, b = b, a + b
fib = fibonacci_generator() print(next(fib)) # 0 print(next(fib)) # 1 print(next(fib)) # 1 print(next(fib)) # 2
3. **Конвейерная обработка (pipeline):**
```python
def parse_logs(log_lines):
for line in log_lines:
if 'ERROR' in line:
yield line
def extract_timestamps(error_lines):
for line in error_lines:
timestamp = line.split()[0]
yield timestamp
# Композиция генераторов
logs = read_large_file('app.log')
errors = parse_logs(logs)
timestamps = extract_timestamps(errors)
for ts in timestamps:
print(f"Ошибка в {ts}")
- Сохранение состояния между вызовами:
def stateful_counter(start=0): count = start while True: increment = yield count if increment is not None: count += increment else: count += 1
counter = stateful_counter(10) next(counter) # Инициализация print(counter.send(5)) # 15 (10 + 5) print(next(counter)) # 16 print(counter.send(-3)) # 13
**Под капотом:** При использовании `yield` Python создает объект-генератор с методами `__next__()` и `send()`. Фрейм функции сохраняется в heap, а не в stack, что позволяет возобновлять выполнение.
**Синтаксический сахар: генераторные выражения**
```python
# Эквивалент генератора в одну строку
squares = (x**2 for x in range(1000000)) # Не выделяет память
sum_of_squares = sum(squares) # Вычисляет на лету
Вывод: Используйте yield когда нужно:
- Обрабатывать данные, которые не помещаются в память
- Создавать ленивые вычисления
- Реализовывать конвейеры обработки
- Сохранять состояние между вызовами
Используйте return для обычных функций, возвращающих готовый результат.