Ответ
Функция-генератор в Python — это функция, которая возвращает специальный итератор (генератор) с помощью ключевого слова yield. В отличие от обычных функций, которые возвращают результат и завершаются, генератор сохраняет своё состояние между вызовами и возобновляет выполнение с места последнего yield.
Ключевые особенности:
- Ленивые вычисления: Элементы генерируются по требованию, что экономит память при работе с большими последовательностями.
- Сохранение состояния: Локальные переменные функции сохраняются между вызовами.
- Итерационный протокол: Генераторы автоматически реализуют методы
__iter__()и__next__().
Пример:
def countdown(n):
"""Генератор, который отсчитывает от n до 1."""
while n > 0:
yield n
n -= 1
# Использование
for number in countdown(5):
print(number) # Вывод: 5 4 3 2 1
# Или вручную
gen = countdown(3)
print(next(gen)) # 3
print(next(gen)) # 2
print(next(gen)) # 1
# print(next(gen)) # Вызовет StopIteration
Практическое применение:
- Обработка больших файлов: Построчное чтение без загрузки всего файла в память.
- Генерация бесконечных последовательностей: Например, поток данных.
- Конвейерная обработка: Создание цепочек генераторов для эффективной обработки данных.
Сравнение с обычной функцией:
# Обычная функция (возвращает весь список)
def get_squares_list(n):
return [i**2 for i in range(n)] # Память O(n)
# Генератор (генерирует значения по одному)
def get_squares_gen(n):
for i in range(n):
yield i**2 # Память O(1) Ответ 18+ 🔞
Смотри, вот тебе про генераторы в Питоне, но без этой сухой академической хуйни. Представь, что обычная функция — это как работяга, который притаскивает тебе сразу целый поддон кирпичей, ебать, и говорит: «Держи, мучайся». А генератор — это хитрая жопа, которая подносит тебе по одному кирпичику, как только ты его попросил. И пока ты не попросил следующий, она стоит, курит и ждёт. Экономия места, понимаешь? Не надо склад строить.
В чём прикол, собственно?
- Ленивость, мать её: Он нихуя не делает, пока ты не скажешь «дай». Идеально, когда данных овердохуища, а память одна.
- Помнит всё: Он как слон, блядь. Запомнил, на каком
yieldостановился, и с этого места продолжает. - Сам умный: Сам в себе реализует всю эту магию с
next()иfor, тебе париться не надо.
Смотри, как это выглядит в деле:
def обратный_отсчёт(n):
"""Эта штука будет тикать от n до единицы."""
while n > 0:
yield n # Вот он, волшебный пиздец! Отдаёт n и засыпает.
n -= 1 # Проснётся тут, когда попросишь следующий элемент.
# Юзаем в цикле, как нормальные люди
for цифра in обратный_отсчёт(5):
print(цифра) # Напечатает: 5, потом 4, потом 3... ну ты понял.
# А можно и вручную дёргать, как из автомата
ген = обратный_отсчёт(3)
print(next(ген)) # 3
print(next(ген)) # 2
print(next(ген)) # 1
# print(next(ген)) # А вот тут будет StopIteration, пиздец, кончилось всё.
Где это реально впаривают?
- Файлы гигабайтные: Читать построчно, а не загружать весь файл в оперативку и охуевать.
- Бесконечные штуки: Типа генератора случайных чисел или стрима данных — ему похуй, он вечный.
- Конвейеры: Один генератор фильтрует, второй преобразует, третий выдаёт — красота, а не жизнь.
Чё там с обычными функциями? Сравниваем:
# Обычная функция-работяга: делает всё и сразу
def квадраты_списком(n):
return [i**2 for i in range(n)] # Бля, создаст список из всех квадратов! Память O(n).
# Генератор-хитрец: работает по запросу
def квадраты_генератором(n):
for i in range(n):
yield i**2 # Выдал один квадрат и отдыхает. Память O(1), ёпта!
Вот и вся магия. Не функция, а мечта ленивого программиста.