В прошлом посте мы восхищались списковыми включениями
[...]. Но у них есть фатальный недостаток: они создают весь список в памяти сразу.Представьте, что вам нужно обработать файл весом 10 ГБ. Если вы попытаетесь загрузить его в список
read_lines(), ваш компьютер скажет "Memory Error" и программа упадет. 💥Тут на помощь приходят Генераторы.
В чем отличие?
🟢📦 Список (
list): Хранит все элементы в памяти. Как готовая книга - все страницы уже напечатаны.🟢⚙️ Генератор: Не хранит данные. Он генерирует следующее значение только тогда, когда вы его попросите. Как рассказчик, который придумывает историю на ходу.
Как создать?
1. Генераторное выражение: Просто замените квадратные скобки
[] на круглые ().
import sys
# Список (создает миллион чисел в памяти)
my_list = [x for x in range(1_000_000)]
print(f"List size: {sys.getsizeof(my_list)} bytes")
# ~8 000 000 байт (8 МБ)
# Генератор (просто формула)
my_gen = (x for x in range(1_000_000))
print(f"Gen size: {sys.getsizeof(my_gen)} bytes")
# ~100 байт (!!!)
Разница колоссальная! Генератор весит копейки, даже если в нем миллиард чисел.
2. Функция с
yield:Если логика сложная, используем функцию. Вместо
return (который убивает функцию и возвращает результат), пишем yield (который ставит на паузу и отдает значение).
def endless_numbers():
n = 0
while True: # Бесконечный цикл!
yield n
n += 1
# Можно брать по одному
gen = endless_numbers()
print(next(gen)) # 0
print(next(gen)) # 1
# Программа не зависнет, несмотря на while True
🚀 Итог: Если вам не нужен доступ ко всем элементам сразу (например, по индексу
list[10]), а вы просто перебираете их в цикле for - всегда используйте генераторы.Знали про
sys.getsizeof? Проверьте свои списки! 😉📲 Мы в MAX
Подписывайтесь на канал 👉@pythonofff
