Ответ
Генератор создается с помощью ключевого слова yield. Когда функция содержит yield, она возвращает специальный объект-генератор, а не выполняет код сразу. Генератор сохраняет свое состояние между вызовами и генерирует значения по одному по мере необходимости (ленивые вычисления).
Пример простого генератора:
def countdown(n):
"""Генератор, который отсчитывает от n до 1."""
while n > 0:
yield n
n -= 1
# Использование
for number in countdown(5):
print(number) # Выведет: 5, 4, 3, 2, 1
Почему это полезно:
- Экономия памяти: Генератор не хранит всю последовательность в памяти, а вычисляет каждое значение на лету. Это критично для работы с большими или бесконечными потоками данных.
- Ленивые вычисления: Код внутри функции выполняется только при обращении к следующему элементу (например, в цикле
forили при вызовеnext()).
Выражение-генератор (generator expression) — это более компактная форма, похожая на list comprehension:
# List comprehension (создает список в памяти)
squares_list = [x**2 for x in range(1000000)]
# Generator expression (ленивое вычисление)
squares_gen = (x**2 for x in range(1000000))
print(next(squares_gen)) # 0
print(next(squares_gen)) # 1 Ответ 18+ 🔞
А, генераторы! Ну это же, ёпта, одна из самых хитрожопых и полезных штук в питоне. Смотри, чтобы не охуеть от их простоты.
Вот представь: обычная функция — это как бутылка водки. Открыл, выпил — всё, пусто, пиздец. А генератор — это как волшебный графин, из которого можно наливать по стопке, когда захочешь, и он никогда не кончается, пока ты не скажешь «стоп». Магия, блядь.
Создаётся эта дичь с помощью слова yield. Как только ты впиндюришь это слово в свою функцию, она превращается не в обычную тётку, а в стриптизёршу, которая выдаёт значения по одному, сохраняя при этом все свои трусы... то есть, состояние. Она возвращает не результат, а специальный объект-генератор, который потом можно тискать.
Вот тебе простейший пример, чтоб мозг не взорвался:
def countdown(n):
"""Генератор, который отсчитывает от n до 1."""
while n > 0:
yield n
n -= 1
# Использование
for number in countdown(5):
print(number) # Выведет: 5, 4, 3, 2, 1
Видишь? Он не вываливает тебе сразу список [5,4,3,2,1] в память. Он лениво, по-царски, выдаёт цифры по одной, когда ты в цикле просишь. Пока не дойдёт до нуля и не накроется медным тазом.
А теперь, блядь, главный вопрос: нахуя это надо?
- Памяти не жрёт, как свинья. Представь, тебе нужно пройтись по миллиону записей. Генератор не будет держать в памяти этот овердохуища список, он будет выдавать элементы по одному, как конвейер. Экономия — мать ебушки-воробушки.
- Ленивые вычисления. Код внутри выполняется только тогда, когда ты говоришь «давай, сука, следующий!» (через
next()или в цикле). Пока не попросил — он спит и не парится. Умно, как мартышлюшка с бананом.
Есть ещё более короткая форма — выражение-генератор. Это как list comprehension, только для бедных и умных. Смотри, не перепутай:
# List comprehension (тупой и жадный: создаёт весь список сразу и грузит память)
squares_list = [x**2 for x in range(1000000)] # Пиздец твоей оперативке!
# Generator expression (хитрый и ленивый: просто обещает посчитать, когда попросят)
squares_gen = (x**2 for x in range(1000000)) # Вот это уже красота!
print(next(squares_gen)) # 0 - на, получи, распишись
print(next(squares_gen)) # 1 - на, ещё одну
Круглые скобочки вместо квадратных — и вуаля, у тебя не список, а генератор. Всё гениальное просто, ёпта. Главное — понять эту идею лени, а потом сам от себя офигеешь, как раньше без этого жил.