Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Генераторы в Python
Генератор — это функция, которая возвращает итератор, выдавая значения по одному с помощью yield вместо return. Это мощный инструмент для создания ленивых (lazy) вычислений.
Основная идея
Основное преимущество генераторов — экономия памяти. Вместо создания всего списка в памяти, генератор создаёт значения на лету:
# Способ 1: Обычная функция со списком (неэффективно)
def get_numbers_list(n):
result = []
for i in range(n):
result.append(i * 2)
return result # Весь список в памяти сразу
# Использование
for num in get_numbers_list(1_000_000):
print(num)
# Способ 2: Генератор (экономия памяти)
def get_numbers_generator(n):
for i in range(n):
yield i * 2 # Выдаёт по одному значению
# Использование
for num in get_numbers_generator(1_000_000):
print(num) # Каждое значение создаётся на месте
С генератором функция не создаёт список из 1 млн элементов в памяти — она выдаёт по одному значению при каждой итерации.
Создание генератора
1. С помощью функции и yield:
def countdown(n):
while n > 0:
yield n
n -= 1
for num in countdown(5):
print(num) # 5, 4, 3, 2, 1
2. Expression генератор (generator expression):
# Похоже на list comprehension, но с () вместо []
numbers = [1, 2, 3, 4, 5]
squared_gen = (x ** 2 for x in numbers) # Генератор
squared_list = [x ** 2 for x in numbers] # Список
print(type(squared_gen)) # <class generator>
print(type(squared_list)) # <class list>
# Значения создаются при итерации
for val in squared_gen:
print(val) # 1, 4, 9, 16, 25
Практические применения
1. Чтение большого файла построчно:
def read_large_file(file_path, chunk_size=1024):
with open(file_path, rb) as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
yield chunk # Выдаём по одному чанку, не загружая весь файл
# Использование
for chunk in read_large_file(huge_file.bin):
process(chunk) # Обрабатываем по кусочкам
2. Бесконечные последовательности:
def infinite_counter(start=0):
n = start
while True:
yield n
n += 1
# Использование
for i, value in enumerate(infinite_counter()):
print(value)
if i > 4:
break # 0, 1, 2, 3, 4
3. Фибоначчи:
def fibonacci(limit=None):
a, b = 0, 1
count = 0
while limit is None or count < limit:
yield a
a, b = b, a + b
count += 1
for fib in fibonacci(10):
print(fib) # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
4. Обработка цепочки трансформаций:
def numbers_gen():
for i in range(10):
yield i
def double(gen):
for value in gen:
yield value * 2
def filter_even(gen):
for value in gen:
if value % 2 == 0:
yield value
# Цепочка — данные обрабатываются по ленивому принципу
for val in filter_even(double(numbers_gen())):
print(val) # 0, 4, 8, 12, 16
Встроенные функции с генераторами
# map() и filter() возвращают итераторы (похоже на генераторы)
nums = [1, 2, 3, 4, 5]
result = map(lambda x: x ** 2, nums) # map object, не список
print(list(result)) # [1, 4, 9, 16, 25]
# zip() — тоже генерирует значения на лету
list1 = [1, 2, 3]
list2 = [a, b, c]
for num, letter in zip(list1, list2):
print(num, letter) # Значения создаются на месте
Методы генератора
def gen():
value = yield 1
print(f"Получено: {value}")
yield 2
g = gen()
result1 = next(g) # Выдаст 1, остановится на yield
result2 = g.send("hello") # Отправит значение в генератор
# Получено: hello
# result2 = 2
Сравнение: Список vs Генератор
import sys
list_comp = [x ** 2 for x in range(1000)] # ~8000 байт
gen_comp = (x ** 2 for x in range(1000)) # ~100 байт
print(sys.getsizeof(list_comp)) # 8856
print(sys.getsizeof(gen_comp)) # 128
Выводы
- Генераторы экономят память — вычисления на лету
- Ленивые вычисления — значения создаются только когда нужны
- Бесконечные последовательности — можно работать без верхнего предела
- Производительность — быстрее всего для больших наборов данных
- Цепочки обработки — элегантная обработка потока данных