Большие файлы: итераторы, генераторы и yield

Вспомните: в прошлой теме вы вытаскивали из текста телефоны и суммы через re, до этого — разбирали даты через datetime и ловили плохие данные в try/except. Все примеры были на десятке строк. Реальный журнал программы или выгрузка из банка — это сотни тысяч и миллионы строк. Сегодня учим программу переваривать такой файл и не съедать при этом всю память.

🎯 После урока сможете: обработать файл на миллион строк по одной строке, написать свою функцию-генератор с yield, собрать конвейер «прочитать → отфильтровать → разобрать» и посчитать итог через sum и max, не создавая огромных списков.

Файл на миллион строк: почему не список

Представьте журнал программы резервного копирования zhurnal.txt. Каждая строка — дата, время, уровень и сообщение. Вот его начало:

2026-09-01 08:15 INFO запуск
2026-09-01 08:16 ERROR диск заполнен
2026-09-02 09:00 INFO копия готова
2026-09-03 10:30 ERROR нет сети
2026-09-03 10:31 INFO повтор

За год таких строк набирается миллион, файл весит сотни мегабайт. Код lines = f.readlines() или text = f.read() сначала целиком загрузит файл в память, а только потом начнёт считать. На слабом ноутбуке программа задумается надолго или упадёт с MemoryError.

Вы уже знаете способ лучше — цикл по самому файлу. Он читает по одной строке: взял строку, обработал, забыл, взял следующую. В памяти одновременно лежит одна строка, сколько бы их ни было в файле.

from pathlib import Path

errors = 0
with Path("zhurnal.txt").open(encoding="utf-8") as f:
    for line in f:
        if " ERROR " in line:
            errors += 1
print(errors)
2
Две схемы рядом. Слева «readlines()»: файл zhurnal.txt на 1 000 000 строк целиком переливается в большой прямоугольник «список в памяти», у которого подпись «1 000 000 строк сразу», и только потом стрелка к блоку «подсчёт». Справа «for line in f»: из того же файла по узкой трубе выходит одна строка, в окошке «в памяти» лежит одна строка, стрелка к блоку «подсчёт», подпись «по одной строке».

Проверьте себя

Контрольный вопрос. Файл журнала весит 3 ГБ. Какой код посчитает строки с ERROR, читая файл по одной строке? Выберите вариант.

Аfor line in f:
Бlines = f.readlines()
Вtext = f.read()
Гlines = list(f)

Подсказка: Три варианта из четырёх сначала собирают весь файл в одну переменную. Найдите тот, что этого не делает.

Онлайн-проверка ответа появится позже

Итератор: iter, next и StopIteration

Почему for умеет идти по файлу, списку и строке одинаково? Потому что все они отдают итератор — объект, который выдаёт элементы по одному. Функция iter() получает итератор, функция next() берёт у него следующий элемент.

it = iter(["Еда", "Такси", "Связь"])
print(next(it))
print(next(it))
print(next(it))
Еда
Такси
Связь

Элементы кончились — следующий next() выбрасывает исключение StopIteration. Его можно поймать, как любое исключение из урока 2.1:

it = iter(["Еда"])
print(next(it))
try:
    next(it)
except StopIteration:
    print("элементы кончились")
Еда
элементы кончились

Цикл for делает ровно это за вас: вызывает iter(), потом next() раз за разом и тихо останавливается на StopIteration. Открытый файл — сам себе итератор: next(f) вернёт очередную строку. Так удобно пропустить строку заголовка перед циклом:

rows = iter(["дата;сумма", "01.09;450", "02.09;300"])  # так же ведёт себя открытый CSV-файл
header = next(rows)          # забрали заголовок
for row in rows:             # цикл продолжит со второй строки
    print(row.split(";")[1])
450
300

Если элемента может не оказаться, передайте в next() второй аргумент — значение по умолчанию. Тогда вместо исключения вернётся оно:

it = iter([])
print(next(it, "пусто"))
пусто
Лента конвейера с тремя коробками «Еда», «Такси», «Связь». Под лентой три вызова next(it), каждый снимает по одной коробке по порядку. Четвёртый вызов next(it) упирается в пустой конец ленты, над ним красная табличка StopIteration. Рядом пометка: next(it, "пусто") вместо ошибки вернёт "пусто".

Проверьте себя

Задание. Что выведет программа? Введите слово.

Исходный код для этого задания:

it = iter(["Аренда", "Свет", "Вода"])
next(it)
print(next(it))

Подсказка: Первый next() забрал элемент, хотя его результат никуда не сохранили. Считайте, какой элемент берёт второй.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Задание. Программа падает с ошибкой. Какое исключение выбросит последняя строка? Введите имя исключения.

Исходный код для этого задания:

it = iter([1])
next(it)
next(it)

Подсказка: Сколько элементов в итераторе и сколько раз вызван next()? Вспомните, что происходит, когда элементы кончились.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Задание. Первая строка выгрузки — заголовок. Что выведет программа? Введите число.

Исходный код для этого задания:

rows = iter(["дата;сумма", "01.09;450", "02.09;300", "03.09;120"])
next(rows)
total = 0
for row in rows:
    total += int(row.split(";")[1])
print(total)

Подсказка: next(rows) до цикла забирает одну строку. Сложите суммы только тех строк, что достались циклу.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Задание. Что выведет программа? Введите число.

Исходный код для этого задания:

it = iter([10, 20])
print(next(it, 0) + next(it, 0) + next(it, 0))

Подсказка: Второй аргумент next() возвращается, когда элементы кончились. Запишите по порядку, что вернёт каждый вызов.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Функция-генератор: yield

Свой итератор проще всего сделать функцией, в которой вместо return стоит yield. Такая функция называется генератором. Вызов не выполняет её тело, а возвращает объект-генератор. Код внутри запускается, когда у генератора просят значение через next() или цикл for: доходит до yield, отдаёт значение и замирает на этом месте до следующей просьбы.

def countdown(n):
    while n > 0:
        yield n
        n -= 1

g = countdown(3)
print(g)
for x in g:
    print(x)
<generator object countdown at 0x…>
3
2
1

Сам print(g) чисел не показал: он сообщил, что в g лежит объект-генератор. Адрес после at 0x у каждого запуска свой. Числа появились, только когда их попросил цикл.

Чтобы увидеть паузы своими глазами, добавим печать внутрь генератора:

def steps():
    print("шаг 1")
    yield "A"
    print("шаг 2")
    yield "B"

g = steps()
print("генератор создан")
print(next(g))
print(next(g))
генератор создан
шаг 1
A
шаг 2
B
  • После g = steps() не напечаталось ничего из функции: тело ещё не начало работать.
  • Каждый next(g) выполняет код до ближайшего yield и возвращает его значение.
  • Когда функция дошла до конца, генератор выбрасывает StopIteration, и цикл for завершается.
  • list(g) соберёт все значения генератора в список — удобно для проверки на маленьких данных, но на миллионе строк список снова займёт всю память.

Главное применение для нас — генератор, который читает файл и отдаёт строки уже очищенными. Снаружи им пользуются как обычным циклом, а файл по-прежнему читается по одной строке:

from pathlib import Path

def read_lines(path):
    with Path(path).open(encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if line:
                yield line

for line in read_lines("zhurnal.txt"):
    print(line[:10])
2026-09-01
2026-09-01
2026-09-02
2026-09-03
2026-09-03

Проверьте себя

Контрольный вопрос. Что окажется в переменной g после строки g = countdown(3)? Выберите вариант.

Исходный код для этого задания:

def countdown(n):
    while n > 0:
        yield n
        n -= 1

g = countdown(3)
Аобъект-генератор, код функции ещё не выполнялся
Бсписок [3, 2, 1]
Вчисло 3
ГNone

Подсказка: Вспомните пример steps(): что напечаталось сразу после создания генератора?

Онлайн-проверка ответа появится позже

Задание. Что выведет программа? Введите список так, как его напечатает Python.

Исходный код для этого задания:

def evens(n):
    for i in range(n):
        if i % 2 == 0:
            yield i

print(list(evens(7)))

Подсказка: Пройдите range(7) по шагам и выпишите числа, на которых срабатывает yield.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Задание. Функция должна отдавать строки по одной, а сейчас возвращает только первую и завершается. Какое слово нужно поставить вместо return? Введите одно слово.

Исходный код для этого задания:

def only_errors(lines):
    for line in lines:
        if "ERROR" in line:
            return line

Подсказка: Вспомните, чем функция-генератор отличается от обычной функции: какое ключевое слово в её теле отдаёт значение наружу?

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Задание. Что выведет программа первой строкой? Введите это слово.

Исходный код для этого задания:

def gen():
    print("внутри")
    yield 1

g = gen()
print("снаружи")
print(next(g))

Подсказка: Разберите по строкам: какая строка программы первой приводит к печати? Вспомните, когда начинает выполняться тело генератора.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Генераторное выражение

Для простых случаев функцию писать не нужно. Генераторное выражение выглядит как списковое включение, только в круглых скобках: (выражение for x in набор if условие). Список из квадратных скобок создаётся целиком сразу, генератор из круглых — выдаёт значения по одному.

amounts = ["450", "380", "н/д", "620"]
lens_list = [len(s) for s in amounts]   # готовый список
lengths = (len(s) for s in amounts)          # генератор, ещё ничего не посчитано
print(lens_list)
print(sum(lengths))
[3, 3, 3, 3]
12

Если генератор — единственный аргумент функции, вторые скобки можно не писать: sum(x for x in ...). Так считают итог прямо по файлу, не заводя список:

from pathlib import Path

with Path("zhurnal.txt").open(encoding="utf-8") as f:
    errors = sum(1 for line in f if " ERROR " in line)
print(errors)
2

Функции sum, max, min принимают генератор так же, как список. У max работает и знакомый параметр key. Ещё две полезные функции отвечают «да или нет»: any(…) — True, если истинно хотя бы одно значение, all(…) — True, если истинны все. Обе останавливаются, как только ответ ясен.

amounts = ["450", "н/д", "620"]
print(any(s.isdigit() for s in amounts))
print(all(s.isdigit() for s in amounts))
True
False

Проверьте себя

Задание. В выгрузке попадаются пропуски «н/д». Что выведет программа? Введите число.

Исходный код для этого задания:

amounts = ["450", "380", "н/д", "620", "—"]
print(sum(int(s) for s in amounts if s.isdigit()))

Подсказка: isdigit() пропускает только строки из цифр. Сложите суммы, которые пройдут фильтр.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Задание. Перед подсчётом программа проверяет выгрузку. Что она выведет? Введите два слова через пробел, как в выводе.

Исходный код для этого задания:

amounts = ["—", "н/д", "", "12р"]
print(any(s.isdigit() for s in amounts), all(s != "" for s in amounts))

Подсказка: Для any ищите хотя бы одну строку из одних цифр, для all проверьте, что пустых строк нет совсем.

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Конвейер: чтение → фильтр → разбор

Самый полезный приём урока — соединить несколько генераторов цепочкой. Каждый делает одно дело и передаёт строку дальше. Строка проходит весь конвейер, и только потом читается следующая: в памяти по-прежнему одна строка.

import re
from datetime import datetime
from pathlib import Path

def read_lines(path):
    with Path(path).open(encoding="utf-8") as f:
        for line in f:
            yield line.strip()

def only_errors(lines):
    for line in lines:
        if " ERROR " in line:
            yield line

def parse(lines):
    for line in lines:
        m = re.search(r"^(\S+ \S+) ERROR (.+)", line)
        if m:
            yield datetime.strptime(m.group(1), "%Y-%m-%d %H:%M"), m.group(2)

errors = parse(only_errors(read_lines("zhurnal.txt")))
for when, text in errors:
    print(when.strftime("%d.%m %H:%M"), text)
01.09 08:16 диск заполнен
03.09 10:30 нет сети
  • read_lines читает файл и чистит строки.
  • only_errors пропускает дальше только строки с ERROR.
  • parse регулярным выражением делит строку на время и текст, а время превращает в datetime по формату %Y-%m-%d %H:%M из урока 2.2. В шаблоне знакомые из урока 2.3 знаки: ^ — начало строки, \S+ — подряд идущие символы без пробелов (дата, потом время).
  • Пока не запущен цикл, ни один генератор не прочитал ни строки: строка errors = … лишь собирает конвейер.
Три блока слева направо, соединённые трубой: read_lines("zhurnal.txt"), only_errors, parse. Над трубой едет одна строка журнала. После read_lines пять строк журнала, после only_errors остаются две строки с ERROR, после parse — пары: datetime(2026, 9, 1, 8, 16) и «диск заполнен», datetime(2026, 9, 3, 10, 30) и «нет сети». Справа потребитель: цикл for или sum/max.

Итог по конвейеру считают теми же sum и max. Например, самая поздняя ошибка:

import re
from datetime import datetime

lines = ["2026-09-01 08:16 ERROR диск заполнен", "2026-09-03 10:30 ERROR нет сети"]
times = (datetime.strptime(re.search(r"^(\S+ \S+)", s).group(1), "%Y-%m-%d %H:%M") for s in lines)
print(max(times))
2026-09-03 10:30:00

Проверьте себя

Задание. Что выведет программа? Введите число.

Исходный код для этого задания:

def only_errors(lines):
    for line in lines:
        if "ERROR" in line:
            yield line

def sizes(lines):
    for line in lines:
        yield int(line.split()[-1])

log = ["INFO копия 120", "ERROR копия 40", "ERROR архив 75", "INFO архив 300"]
print(sum(sizes(only_errors(log))))

Подсказка: Пройдите конвейер по шагам: какие строки пропустит only_errors, какое число sizes достанет из каждой?

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Задание. Программа ищет день, когда за одну покупку потратили больше всего. Что она выведет? Введите дату так, как её напечатает программа.

Исходный код для этого задания:

import re

log = ["01.09 чек: 450 руб", "02.09 возврат", "03.09 чек: 1 280 руб", "05.09 чек: 990 руб"]

def checks(lines):
    for line in lines:
        m = re.search(r"(\d\d\.\d\d) чек: ([\d ]+) руб", line)
        if m:
            yield m.group(1), int(m.group(2).replace(" ", ""))

def by_amount(pair):
    return pair[1]

day, amount = max(checks(log), key=by_amount)
print(day)

Подсказка: Выпишите пары, которые отдаст checks: какие строки подходят под шаблон и что станет с пробелом внутри суммы? by_amount возвращает второй элемент пары — по нему max и сравнивает.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

Онлайн-проверка ответа появится позже

Ловушка: генератор одноразовый

Генератор выдаёт каждое значение ровно один раз. Прошли по нему до конца — он пуст, второй проход не даст ничего. Ошибки не будет, просто пустой результат:

nums = (int(s) for s in ["450", "380", "620"])
print(sum(nums))
print(sum(nums))
1450
0

С файлом то же самое: второй for line in f по уже прочитанному файлу не выполнится ни разу. Три способа выйти из ловушки:

  • посчитать всё за один проход — завести несколько переменных и обновлять их в одном цикле;
  • создать генератор заново — ещё раз вызвать функцию read_lines("zhurnal.txt"), она снова откроет файл;
  • если данных мало — сохранить их в список list(...) и ходить по нему сколько угодно.
from pathlib import Path

total = 0
errors = 0
with Path("zhurnal.txt").open(encoding="utf-8") as f:
    for line in f:
        total += 1
        if " ERROR " in line:
            errors += 1
print(errors, "из", total)
2 из 5

Сделайте у себя файл zhurnal.txt из начала урока, размножьте строки циклом до миллиона (f.write(line) в for i in range(200_000)) и сравните: сколько думает readlines() и сколько — цикл по файлу. Посмотрите память в диспетчере задач.

Проверьте себя

Задание. Что выведет второй print? Введите число.

Исходный код для этого задания:

nums = (x * 2 for x in [1, 2, 3])
print(max(nums))
print(len(list(nums)))

Подсказка: max прошёл генератор до конца, чтобы найти наибольшее. Что осталось в генераторе после этого?

✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.

Онлайн-проверка ответа появится позже

Контрольный вопрос. Программа считает средний чек и падает с ZeroDivisionError. Какая правка первой строки её починит? Выберите вариант.

Исходный код для этого задания:

amounts = (int(s) for s in ["450", "380", "620"])
total = sum(amounts)
count = len(list(amounts))
print(total / count)
Аamounts = [int(s) for s in [«450», «380», «620»]]
Бamounts = (int(s) for s in («450», «380», «620»))
Вamounts = iter(int(s) for s in [«450», «380», «620»])
Гamounts = (float(s) for s in [«450», «380», «620»])

Подсказка: Почему count оказался нулём? Нужен вариант, по которому можно пройти дважды.

Онлайн-проверка ответа появится позже

Проектные миссии

Задание. Проектная миссия «Ошибки за неделю». Сохраните данные ниже в файл server.log (кодировка utf-8). Напишите конвейер из трёх функций-генераторов: read_lines(path) читает файл по строке и отдаёт непустые строки без пробелов по краям; only_errors(lines) пропускает строки с уровнем ERROR; parse(lines) через re и datetime.strptime превращает строку в пару (время, текст). По конвейеру посчитайте через sum, сколько ошибок случилось с 8 по 14 сентября 2026 года включительно. Списков из всех строк файла не создавать. Потом запустите утилиту на журнале своей программы. Приложите файл программы .py; в поле ответа — число.

Принято, если:
1. число совпадает с эталоном;
2. приложен .py, который его выдаёт на данных из условия.

Самопроверка перед сдачей (преподаватель смотрит на занятии):
3. три отдельные функции с yield, соединённые цепочкой; файл читается циклом по строкам, без readlines() и read().

2026-09-01 10:56 ERROR нет сети

2026-09-01 18:45 INFO запуск

2026-09-02 01:38 ERROR нет доступа

2026-09-02 02:38 INFO запуск

2026-09-02 05:55 INFO запуск

2026-09-02 09:16 ERROR диск заполнен

2026-09-02 11:49 INFO проверка ок

2026-09-03 01:10 ERROR файл занят

2026-09-03 01:15 WARNING мало места

2026-09-03 07:00 ERROR нет сети

2026-09-03 19:34 ERROR нет сети

2026-09-04 05:47 INFO запуск

2026-09-04 15:00 INFO запуск

2026-09-05 03:40 INFO проверка ок

2026-09-05 19:16 WARNING медленная сеть

2026-09-06 12:02 INFO запуск

2026-09-06 14:46 INFO проверка ок

2026-09-07 02:37 ERROR нет доступа

2026-09-07 04:31 INFO проверка ок

2026-09-08 13:20 WARNING мало места

2026-09-08 13:39 WARNING мало места

2026-09-09 20:37 ERROR диск заполнен

2026-09-10 21:47 WARNING мало места

2026-09-10 22:46 ERROR нет доступа

2026-09-11 10:11 INFO копия готова

2026-09-11 12:55 INFO запуск

2026-09-12 01:47 INFO копия готова

2026-09-12 01:53 ERROR нет доступа

2026-09-12 05:25 WARNING медленная сеть

2026-09-12 12:43 INFO запуск

2026-09-12 19:33 ERROR нет сети

2026-09-12 20:07 INFO запуск

2026-09-13 02:55 INFO копия готова

2026-09-13 07:37 INFO копия готова

2026-09-13 18:26 WARNING мало места

2026-09-13 22:59 WARNING мало места

2026-09-14 13:03 ERROR файл занят

2026-09-14 17:52 WARNING медленная сеть

2026-09-14 20:55 ERROR нет сети

2026-09-15 10:30 INFO проверка ок

2026-09-15 13:01 ERROR диск заполнен

2026-09-15 16:10 ERROR файл занят

2026-09-15 17:11 WARNING мало места

2026-09-15 20:46 WARNING мало места

2026-09-16 05:39 INFO проверка ок

2026-09-17 14:55 INFO проверка ок

2026-09-17 16:25 WARNING медленная сеть

2026-09-17 21:05 INFO запуск

2026-09-18 06:47 INFO проверка ок

2026-09-18 08:48 INFO запуск

2026-09-18 16:17 WARNING мало места

2026-09-18 16:21 INFO копия готова

2026-09-19 22:53 WARNING медленная сеть

2026-09-20 04:36 INFO копия готова

2026-09-20 16:33 ERROR диск заполнен

2026-09-21 17:16 ERROR файл занят

Подсказка: Сравнивайте datetime, а не строки: граница «14 сентября включительно» — это всё, что раньше datetime(2026, 9, 15). Проверьте конвейер сначала на пяти строках из урока.

✅ Готово, если: ответ раскрывает то, что просит критерий приёмки в задании выше.

Онлайн-проверка ответа появится позже

Задание. Проектная миссия «Траты по выходным». Банк выгрузил платежи за сентябрь: сохраните данные ниже в файл platezhi.csv (кодировка utf-8, разделитель ;, первая строка — заголовок). В столбце суммы попадается мусор: пусто, «н/д», «—», опечатки; у больших сумм есть пробел между тысячами. Напишите генератор read_rows(path): пропускает заголовок через next(f) и отдаёт строки списком ячеек. Второй генератор amounts(rows) убирает пробелы из суммы, переводит её в int, мусор пропускает через try/except ValueError и отдаёт только платежи, сделанные в субботу или воскресенье (datetime.strptime и weekday()). Итог посчитайте sum по конвейеру. Приложите файл программы .py; в поле ответа — число.

Принято, если:
1. число совпадает с эталоном;
2. приложен .py, который его выдаёт на данных из условия.

Самопроверка перед сдачей (преподаватель смотрит на занятии):
3. программа не падает ни на одной строке с мусором, а плохие строки не молча теряются в общем except — ловится именно ValueError.

id;дата;сумма

1;16.09.2026;7139

2;23.09.2026;н/д

3;04.09.2026;17 863

4;25.09.2026;21114

5;28.09.2026;20025

6;25.09.2026;11734

7;04.09.2026;24903

8;07.09.2026;21367

9;05.09.2026;12o0

10;04.09.2026;13 302

11;20.09.2026;6023

12;04.09.2026;23898

13;13.09.2026;19 558

14;27.09.2026;16120

15;27.09.2026;19512

16;11.09.2026;7 786

17;16.09.2026;15 689

18;29.09.2026;20388

19;15.09.2026;6 295

20;24.09.2026;19 850

21;20.09.2026;24609

22;28.09.2026;19164

23;21.09.2026;ошибка

24;12.09.2026;9669

25;03.09.2026;10791

26;05.09.2026;384

27;23.09.2026;19751

28;16.09.2026;18657

29;23.09.2026;3 624

30;15.09.2026;3805

31;28.09.2026;—

32;29.09.2026;н/д

33;10.09.2026;23007

34;03.09.2026;22788

35;02.09.2026;18051

36;23.09.2026;1 926

37;20.09.2026;15 628

38;26.09.2026;

39;05.09.2026;20727

40;25.09.2026;21328

41;02.09.2026;1771

42;23.09.2026;22 986

43;18.09.2026;12o0

44;09.09.2026;20 903

45;04.09.2026;10 738

46;24.09.2026;9268

47;28.09.2026;22976

48;27.09.2026;н/д

49;22.09.2026;1 041

50;04.09.2026;19722

51;25.09.2026;19 371

52;13.09.2026;13690

Подсказка: weekday() возвращает 0 для понедельника; какие номера у субботы и воскресенья — проверьте на известной дате. Сначала выведите пары (дата, сумма) для первых строк и убедитесь, что мусор отсеялся.

✅ Готово, если: ответ раскрывает то, что просит критерий приёмки в задании выше.

Онлайн-проверка ответа появится позже

Что дальше

Теперь вы умеете обрабатывать файл любого размера по одной строке, получать элементы через iter и next, писать функции-генераторы с yield, собирать из них конвейер «чтение → фильтр → разбор» и считать итог через sum и max. И помните: генератор проходится один раз. Глава 2 закончена — ваши программы не падают на плохих данных, считают даты, вытаскивают нужное из текста и не боятся больших файлов. Следующая глава курса — в навигаторе.

← Назад · ↑ В начало урока · ⌂ К навигатору курса · Вперёд →

Школа Виктора Комлева