Функции в Python и работа с файлами
Разбираем def, параметры и return, локальные переменные и рекурсию — и учим программу читать и записывать файлы через open и with.
Представь: в классе 28 учеников, и для каждого нужно посчитать средний балл по шести оценкам. Без функций это шесть строк кода, скопированных 28 раз, — почти 170 строк, в которых легко потерять одну. А когда оценки решат читать из файла data.txt, править придётся все 28 копий подряд. Выход простой: пишем функцию average один раз и вызываем её 28 раз с разными списками. В этом уроке разберём def, параметры и return, коротко заглянем в рекурсию и научим программу читать и записывать файлы.
Функции: def, параметры и return
Функция — это блок кода с именем, который можно вызывать сколько угодно раз. Объявление начинается с ключевого слова def: строка def average(grades): создаёт функцию с именем average, а grades здесь — параметр, имя, в которое при вызове придёт значение. Конкретные значения при вызове называют аргументами: в average([5, 4, 5, 4, 5, 4]) аргумент — этот самый список из шести оценок. Чтобы функция отдала результат наружу, нужен return: return sum(grades) / len(grades) вернёт 27 делить на 6, то есть 4.5. Функций в программе может быть сколько угодно, а return может встречаться в разных ветках if — как только Python дошёл до него, функция завершается.
Локальные переменные и рекурсия
Переменная, созданная внутри функции, локальная: после выхода из функции её не существует — total из average снаружи не виден. Читать глобальную переменную из функции можно и без разрешений, а вот менять — только после строки global: иначе Python создаст локальную с тем же именем, и глобальная останется старой. Вторая важная штука — рекурсия: функция вызывает саму себя. Классический пример — факториал: def fact(n): при n == 1 возвращаем 1, иначе return n * fact(n - 1). Вызов fact(5) запускает цепочку из пяти вызовов: fact(5) просит fact(4), тот — fact(3) и так до fact(1), где срабатывает условие остановки, и значения возвращаются обратно: 1, 2, 6, 24 и наконец 120.
| Что пишем | Что делает | Пример |
|---|---|---|
| open("data.txt", "r") | открывает файл для чтения; "r" — режим по умолчанию | with open("data.txt") as f: |
| f.read() | весь текст файла одной строкой | text = f.read() |
| f.readlines() | список строк файла | lines = f.readlines() |
| f.write("5;4") | записывает строку в файл | перевод строки надо добавить самому |
| "w" / "a" | запись с затиранием старого / дозапись в конец | open("log.txt", "a") |
Прогон функции: стек вызовов
Следи за жизнью одного вызова. Программа встречает average([5, 4, 5]) и прыгает в тело функции, положив список в параметр grades. Внутри создаётся локальная переменная, return отдаёт число вызывающей строке — и жизнь функции кончается: её локальные переменные стираются. Если из average вызвать sq, а из sq — abs, получится стек вызовов: стопка, где работает только верхняя «тарелка». Рекурсия строит ту же стопку: fact(5) зовёт fact(4), тот fact(3) — пять вызовов в стопке, затем значения начинают возвращаться снизу вверх: 1, 2, 6, 24, 120. Глубина рекурсии — высота стопки, и у неё есть предел, поэтому рекурсия без условия остановки падает с ошибкой.
Параметры умеют иметь значения по умолчанию: def price(t, k=100) вернёт t · 100, если второй аргумент не передали, и t · k, если передали. Аргументы бывают позиционные — по порядку — и именованные: price(3, k=50) передаёт 3 по позиции и 50 по имени. Именованные делают вызовы читаемыми: видно по имени, что именно передаёшь. А значение по умолчанию вычисляется один раз при объявлении — именно поэтому пустой список в дефолте опасен.
Разбор типовой задачи
Задача в духе ЕГЭ: функция объявлена так — при n = 1 возвращается 1, иначе F(n) = F(n − 1) + 2 · n. Что вернёт F(4)? Считаем от базы вверх по шагам.
- База: F(1) = 1 — условие остановки срабатывает первым.
- Шаг вверх: подставляем F(1) в формулу для n = 2.
- Следующий шаг для n = 3.
- Последний шаг для n = 4.
- Проверка числа вызовов: цепочка тянется от 4 вниз до 1 — четыре вызова.
- Ответ: 19. Схема всегда одна: база, шаги вверх, ответ.
Такими функциями на экзамене кодируют даже суммы цифр числа. Разминка на ту же схему: функция D(n) возвращает 0 при n = 0, иначе D(n) = D(n // 10) + n % 10 — сумма цифр. Прогон D(2026): D(202) + 6, затем D(20) + 2, затем D(2) + 0, затем D(0) + 2 — итого 10. База, четыре шага, ответ: полминуты работы. Меняется формула шага — меняется арифметика, но не схема прогона.
return умеет отдавать и несколько значений сразу: return mn, mx вернёт пару, которую вызывающий код распакует в две переменные. А если return не встретился, функция вернёт None — помни это, когда пишешь функцию-«процедуру», которая только печатает результат на экран.
Файлы: читаем данные построчно
Реальные данные приходят файлами, и классическая связка чтения выглядит так:
with open("marks.txt") as f: for line in f: parts = line.strip().split(";") name = parts[0] marks = [int(x) for x in parts[1:]] print(name, sum(marks) / len(marks)) Строка за строкой: strip убирает невидимый перевод строки в конце, split(";") режет строку по точкам с запятой, parts[0] — имя, а срез parts[1:] — оценки, которые int превращает в числа.
Запись зеркальна: with open("result.txt", "w") as f и f.write("4.5") — только перевод строки в файл добавь руками через f.write("\n"). Цикл for по файлу читает его построчно, поэтому даже большой файл не съест память целиком: в ней живёт одна текущая строка.
Если файл маленький, короче прочитать его целиком: numbers = [int(x) for x in open("data.txt").read().split()] — одна строка превращает файл в список чисел. Для больших файлов этот путь расточителен: весь текст ляжет в память сразу, поэтому там остаётся построчный цикл. Выбирай по размеру данных, а не по вкусу.
Страница файла содержит 40 строк по 50 символов, кодировка однобайтовая. Сколько КБ весит страница? Считай 1 КБ = 1024 байта.
Словарь урока
- def#
- ключевое слово объявления функции
- Параметр#
- имя в скобках при объявлении, принимает значение при вызове
- return#
- возврат значения и завершение функции
- Стек вызовов#
- стопка активных вызовов: работает только верхний
- Условие остановки#
- база рекурсии, где цепочка вызовов заканчивается
- Режим файла#
- правило открытия: чтение, запись с затиранием или дозапись
Как это спрашивают на контрольной и ЕГЭ
- Что выведет программа с функцией? Первый взгляд — есть ли return внутри.
- Сколько раз вызовется рекурсивная функция? Считай цепочку от аргумента до базы.
- Перепиши повторяющееся вычисление через функцию: вынеси код, верни return.
- Допиши программу чтения файла: with open, цикл по строкам, split по разделителю.
- Найди ошибку: функция возвращает None. Ищи пропущенный return или return не в той ветке.
На экзамене функции редко проверяют в одиночку: они спрятаны внутри задач на файлы, рекурсию и обработку данных. Навык «прочитать объявление, найти базу рекурсии, сделать прогон» экономит время сразу в нескольких заданиях.
Отдельный жанр задач — «найди вывод программы» с вложенными вызовами: f(g(3)), где g возвращает квадрат, а f — половину. Считай изнутри наружу: сначала g(3) даст 9, затем f(9) даст 4.5. Порядок вычислений в таких задачах важнее знаний синтаксиса.
Теперь собери всё вместе. Чтение данных: with open("marks.txt") as f, дальше for line in f: — внутри line.strip() убирает перевод строки, line.split(";") режет строку на части, например имя и шесть оценок. Каждую оценку превращаем в число функцией int, после этого работает обычная average. Запись зеркальна: open("result.txt", "w") и f.write("4.5"), а если результат надо дописывать, а не затирать, берём режим "a". Домашняя задача на сегодня: перепиши программу среднего балла так, чтобы оценки приходили из файла, а результат уходил в другой файл. Это ровно та связка «функции плюс файлы», которую проверяют на экзамене.
Проверь себя
Клавиши 1–9 выбирают вариант, Enter — «Проверить»
1 Что напечатает print(f(5)), если функция объявлена как def f(x): x * 2 без return?
2 Функция объявлена как def price(t, k=100): return t * k. Что вернёт вызов price(3)?
3 После выполнения блока with open("data.txt") as f: файл закрывается автоматически.
4 Какие утверждения про функции верны?
5 Расставь шаги чтения данных из файла по порядку.
6 Сопоставь конструкцию и её смысл.
Нажми на элемент слева, затем на его пару справа. Повторное нажатие отменяет связь.
7 Вставь пропущенные слова.
Выбери подходящее слово в каждом пропуске.
Значение из функции наружу отдаёт оператор , а переменная, созданная только внутри функции, называется .
Было понятно? Скажи — так мы видим, какие темы переписать.
Частые вопросы
Чем отличается параметр от аргумента в Python?
Параметр — это имя в скобках при объявлении def, «ячейка», в которую придёт значение. Аргумент — конкретное значение при вызове: в def sq(n) параметр n, а в вызове sq(7) аргумент — число 7.
Что вернёт функция, в которой забыли return?
None — то есть «ничего». Код внутри выполнится, print даже что-то покажет, но использовать результат нельзя: выражение f(5) + 1 упадёт с ошибкой TypeError.
Почему нельзя писать def add(x, lst=[])?
Дефолтный список создаётся один раз при объявлении функции, и все вызовы без аргумента меняют один и тот же список — элементы накапливаются между вызовами. Правильно писать lst=None и создавать список внутри функции.
Зачем with, если можно просто open и close?
with закроет файл автоматически при выходе из блока, даже если внутри случилась ошибка. Ручной close легко забыть — тогда файл останется занят, а данные могут не дозаписаться до конца.