Функции, строки и работа с файлами

Три навыка, без которых не написать ни одной серьёзной программы: разбивать код на функции, обрабатывать текст и работать с данными.

Функция — именованный блок кода, который принимает аргументы, выполняет действие и может вернуть результат; главный инструмент борьбы со сложностью.

Зачем это нужно

Когда программа вырастает, держать всё в голове невозможно. Функции позволяют разбить задачу на понятные кусочки, дать им имена и переиспользовать. Строки — это тексты, имена, ответы пользователя; их обработка встречается в каждой второй задаче. Файлы — способ сохранять данные между запусками. Эти три темы — рабочая повседневность программиста и основа заданий на обработку данных.

Главная идея, объединяющая весь урок, — борьба со сложностью через разбиение. Человеческий ум не способен одновременно удерживать сотню деталей, и единственный способ написать большую программу — резать её на части, каждая из которых умещается в голове целиком. Функция — основной инструмент такого разбиения: вы прячете кусок логики за понятным именем, и дальше думаете о нём как о «чёрном ящике» — что подаёшь, что получаешь, — не отвлекаясь на внутреннее устройство. Именно так строится любой серьёзный код: не одной простынёй, а как набор маленьких, проверяемых по отдельности функций. Строки и файлы добавляют к этому умение работать с реальными данными — ведь данные приходят к программе как текст (ввод пользователя, содержимое файла) и должны где-то сохраняться. Освоив эти три навыка, вы перестаёте писать «скрипты на один раз» и начинаете строить программы, которые можно развивать и поддерживать.

Функции: имя для куска логики

Функция получает данные через параметры и возвращает результат через return. Хорошая функция делает одно понятное дело. Напишем функцию, проверяющую, простое ли число — её можно вызывать сколько угодно раз:

def is_prime(n):
    if n < 2:
        return False
    d = 2
    while d * d <= n:          # достаточно проверять до корня из n
        if n % d == 0:
            return False
        d += 1
    return True

for x in range(2, 20):
    if is_prime(x):
        print(x, end=" ")
print()
print("простых до 20 столько:", sum(1 for x in range(2, 20) if is_prime(x)))

Вывод:

2 3 5 7 11 13 17 19
простых до 20 столько: 8

Параметры по умолчанию и несколько возвращаемых значений

Параметрам можно задать значения по умолчанию, а вернуть можно сразу несколько величин (через кортеж). Это делает функции гибкими:

def stats(numbers, ndigits=2):
    total = sum(numbers)
    average = round(total / len(numbers), ndigits)
    return total, average, max(numbers), min(numbers)

s, avg, hi, lo = stats([4, 8, 15, 16, 23, 42])
print("сумма:", s, " среднее:", avg, " макс:", hi, " мин:", lo)
# вызов с другим округлением
print(stats([1, 2, 2], ndigits=4))

Вывод:

сумма: 108  среднее: 18.0  макс: 42  мин: 4
(5, 1.6667, 2, 1)

Область видимости: локальное и глобальное

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

counter = 100          # глобальная

def demo():
    counter = 5        # своя, локальная — не трогает глобальную
    return counter

print("внутри функции:", demo())
print("снаружи:", counter)   # глобальная не изменилась

Вывод:

внутри функции: 5
снаружи: 100

Строки: методы, которые решают половину задач

Строки неизменяемы, но богаты методами. split режет на части, join склеивает, strip убирает пробелы по краям, replace заменяет, upper/lower меняют регистр. Освойте их — и обработка текста станет лёгкой:

line = "  Иванов; Петров; Сидоров  "
names = line.strip().split(";")          # убрали пробелы, разрезали
names = [n.strip() for n in names]       # подчистили каждое
print("список:", names)
print("через запятую:", ", ".join(names))
print("заглавными:", names[0].upper())
print("начинается на 'Ив'?", names[0].startswith("Ив"))

Вывод:

список: ['Иванов', 'Петров', 'Сидоров']
через запятую: Иванов, Петров, Сидоров
заглавными: ИВАНОВ
начинается на 'Ив'? True

Форматирование строк (f-строки)

f-строки — самый удобный способ подставлять значения в текст. Внутри фигурных скобок можно писать выражения и указывать формат вывода:

name = "Аня"
score = 87.5
print(f"{name} набрала {score} баллов")
print(f"в процентах: {score/100:.1%}")     # формат процента
print(f"число pi: {3.14159265:.3f}")        # три знака после запятой
print(f"{42:>6}|{42:<6}|")                   # выравнивание по ширине 6

Вывод:

Аня набрала 87.5 баллов
в процентах: 87.5%
число pi: 3.142
    42|42    |

Файлы: сохраняем и читаем данные

Файлы позволяют данным пережить завершение программы. Открывают файл конструкцией with open(...) as f — она гарантирует, что файл будет закрыт. Запишем числа в файл и прочитаем обратно. В песочнице файл создаётся во временной памяти браузера — код полностью рабочий:

# запись
with open("data.txt", "w", encoding="utf-8") as f:
    for x in [10, 20, 30, 40]:
        f.write(str(x) + "\n")        # каждое число на своей строке

# чтение и обработка
total = 0
with open("data.txt", "r", encoding="utf-8") as f:
    for line in f:
        total += int(line.strip())    # strip убирает перевод строки

print("сумма чисел из файла:", total)

Вывод:

сумма чисел из файла: 100

Попробуй сам

Соберём всё в одну мини-программу: функция считает статистику по строке чисел, разделённых пробелами. Это типичный шаблон задач «на вход дана строка чисел».

def analyze(raw):
    numbers = [int(x) for x in raw.split()]
    return {
        "count": len(numbers),
        "sum": sum(numbers),
        "max": max(numbers),
        "even": [x for x in numbers if x % 2 == 0],
    }

result = analyze("7 2 9 4 4 11 6")
for key, value in result.items():
    print(f"{key}: {value}")

Вывод:

count: 7
sum: 43
max: 11
even: [2, 4, 4, 6]

Частые ошибки

  • Забывают return. Без него функция возвращает None, и результат «теряется».
  • Пытаются изменить строку по индексу. Строки неизменяемы; методы возвращают новую строку, а не меняют старую.
  • Не убирают перевод строки при чтении файла. Каждая строка из файла оканчивается \n; используйте .strip().
  • Путают локальные и глобальные переменные. Присваивание внутри функции создаёт локальную переменную, не затрагивая глобальную.

Итоги

  • Функция инкапсулирует логику: параметры на входе, return на выходе; можно возвращать несколько значений.
  • Локальные переменные живут только внутри функции — это защищает код от путаницы.
  • Методы строк (split, join, strip, replace) и f-строки покрывают большинство задач обработки текста.
  • Файлы открывают через with open(...); при чтении не забывайте strip().
Проверьте себя
1. Что вернёт функция, в которой нет инструкции return?
A0
BПустую строку
CNone
DОшибку
2. Что делает метод строки split() без аргументов?
AУдаляет пробелы по краям
BРазбивает строку на список слов по пробелам
CПереводит строку в верхний регистр
DСоединяет слова в строку
3. Зачем при чтении строки из файла применяют .strip()?
AЧтобы перевести в число
BЧтобы убрать символ перевода строки и лишние пробелы по краям
CЧтобы ускорить чтение
DЧтобы закрыть файл
Поддержать проект