← Назад к вопросам

В чем разница между генератором и списком?

1.2 Junior🔥 241 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между генератором и списком

Это фундаментальное различие в Python, касающееся того, как данные хранятся и обрабатываются в памяти. Несмотря на то, что оба используются для итерации, они работают совершенно по-разному.

Списки (List)

Список — это структура данных, которая хранит ВСЕ элементы в памяти сразу. Это жадный (eager) подход.

Характеристики:

  • Хранит все элементы в памяти
  • Может быть индексирован
  • Может быть изменяемым (mutable)
  • Использует больше памяти
  • Быстрый доступ к элементам
# Создание списка — все 1000000 элементов в памяти сразу
my_list = [i for i in range(1000000)]

print(len(my_list))          # Быстро — уже в памяти
print(my_list[999999])       # Быстро — прямой доступ
print(my_list[0:10])         # Быстро — срез работает
my_list[0] = 999             # Можно изменять
my_list.append(1000000)      # Можно добавлять

Генераторы (Generator)

Генератор — это функция, которая возвращает значения по одному, по требованию. Это ленивый (lazy) подход.

Характеристики:

  • Генерирует значения по мере надобности
  • Нельзя индексировать
  • Нельзя изменять
  • Использует минимум памяти
  • Медленнее доступ (нужно вычислять)
# Создание генератора — ничего не в памяти
def my_generator():
    for i in range(1000000):
        yield i

gen = my_generator()

print(len(gen))              # ОШИБКА! Нет len() у генератора
print(gen[999999])           # ОШИБКА! Нет индексирования

# Получить первый элемент
first = next(gen)            # Вычисляется по требованию

# Итерировать
for value in gen:
    print(value)             # По одному элементу за раз

Таблица различий

АспектСписокГенератор
ХранениеВсе в памятиПо мере надобности
ПамятьO(n) — все элементыO(1) — только текущее
Скорость созданияМедленно (считает всё)Быстро (ничего не считает)
ДоступПрямой (my_list[5])Только последовательный
ИндексированиеПоддерживаетсяНЕ поддерживается
СлайсингПоддерживаетсяНЕ поддерживается
ИтерированиеМожно много разТолько один раз
ИзменениеМожно менять элементыНельзя
len()РаботаетНе работает
Когда считаетсяПри созданииПри доступе (ленивое)

Практические примеры

Пример 1: Потребление памяти

import sys

# СПИСОК — всё в памяти
my_list = [i for i in range(1000000)]
print(f"Размер списка: {sys.getsizeof(my_list):,} байт")  # ~8 MB

# ГЕНЕРАТОР — минимум памяти
def my_gen():
    for i in range(1000000):
        yield i

gen = my_gen()
print(f"Размер генератора: {sys.getsizeof(gen)} байт")  # ~128 байт

# Разница: 8MB vs 128 байт!

Пример 2: Скорость создания

import time

# СПИСОК — долго создавать
start = time.time()
my_list = [i**2 for i in range(10000000)]
end = time.time()
print(f"Список создан за {end - start:.3f}s")  # ~0.5s

# ГЕНЕРАТОР — практически мгновенно
start = time.time()
def my_gen():
    for i in range(10000000):
        yield i**2
gen = my_gen()
end = time.time()
print(f"Генератор создан за {end - start:.6f}s")  # ~0.000001s

Пример 3: Итерирование

# СПИСОК — можно итерировать много раз
my_list = [1, 2, 3, 4, 5]
for x in my_list:
    print(x)  # 1 2 3 4 5
for x in my_list:
    print(x)  # 1 2 3 4 5 — снова работает!

# ГЕНЕРАТОР — только один раз
def my_gen():
    for i in [1, 2, 3, 4, 5]:
        yield i

gen = my_gen()
for x in gen:
    print(x)  # 1 2 3 4 5
for x in gen:
    print(x)  # (ничего!) — генератор исчерпан

Пример 4: Чтение большого файла

# ПЛОХО — список загружает файл целиком
def read_large_file_list(filename):
    with open(filename) as f:
        lines = f.readlines()  # ВСЕ строки в памяти!
    return lines

# ХОРОШО — генератор читает по одной строке
def read_large_file_generator(filename):
    with open(filename) as f:
        for line in f:
            yield line.strip()

# Использование
for line in read_large_file_generator(huge_file.txt):
    process(line)  # Обрабатываем по одной строке
    # Предыдущие строки уже забыли из памяти

Синтаксис генераторов

Способ 1: Generator Function (функция с yield)

def simple_generator():
    print("Шаг 1")
    yield 1
    print("Шаг 2")
    yield 2
    print("Шаг 3")
    yield 3

gen = simple_generator()
print(next(gen))  # Шаг 1 → 1
print(next(gen))  # Шаг 2 → 2
print(next(gen))  # Шаг 3 → 3
# next(gen) → StopIteration

Способ 2: Generator Expression (выражение)

# Список (list comprehension)
my_list = [i**2 for i in range(5)]
print(my_list)  # [0, 1, 4, 9, 16]

# Генератор (generator expression) — почти всё равно!
my_gen = (i**2 for i in range(5))  # Скобки вместо квадратных
print(next(my_gen))  # 0
print(next(my_gen))  # 1

Когда использовать что

Используйте СПИСОК если:

  • Нужно много раз обращаться к одним и тем же элементам
  • Нужна индексация (list[5])
  • Нужно изменять элементы
  • Данных немного
  • Нужна скорость доступа
users = [fetch_user(i) for i in range(10)]  # Малое количество
print(users[5].name)  # Прямой доступ

Используйте ГЕНЕРАТОР если:

  • Данных очень много (файлы, базы данных)
  • Обрабатываете данные один раз
  • Экономите память критична
  • Данные дорого генерируются
  • Нужна лень (lazy evaluation)
def process_large_dataset(filename):
    for line in read_large_file_generator(filename):
        yield process_line(line)

# Обрабатываем по одной строке, не загружая всё в память

Практический пример: Фильтрирование данных

# СПИСОК — загружает всё в памяти
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_list = [x for x in data if x % 2 == 0]
# Результат: [2, 4, 6, 8, 10] — все в памяти

# ГЕНЕРАТОР — ленивое вычисление
def even_generator(data):
    for x in data:
        if x % 2 == 0:
            yield x

even_gen = even_generator(data)
# Результат: объект, который считает по требованию
for num in even_gen:
    print(num)  # 2, 4, 6, 8, 10 — по одному

Заключение

Список — это полная загрузка всех данных в память для быстрого доступа.

Генератор — это ленивое вычисление значений по мере надобности для экономии памяти.

Выбирайте генераторы для больших данных, списки для малых и часто используемых данных. На практике, если вы обрабатываете данные один раз (линия по линии, строка по строке), генератор — это ваш выбор.

В чем разница между генератором и списком? | PrepBro