Глиф Учебники

Урок 10. Файлы и исключения

Курс «Python» · урок 10 из 10 · 4 минуты чтения

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

Запись в файл

Файл открывают функцией open — с именем файла и режимом: "w" — запись. Удобнее всего — внутри with: когда блок закончится, файл закроется сам, даже если в блоке случилась ошибка.

Python
with open("notes.txt", "w", encoding="utf-8") as f:
    f.write("Первая строка\n")
    f.write("Вторая строка\n")
print("Файл записан")
Вывод
Файл записан

Файл notes.txt появится в текущей папке — обычно это папка, из которой запущена программа. Подробнее о том, где ищется файл, — в справке Как прочитать и записать файл.

Режим "w" стирает всё, что было в файле, ещё при открытии. Если файл с таким именем уже есть, его старое содержимое пропадёт без предупреждения. Чтобы дописать в конец, откройте файл в режиме "a".

Режимы открытия

РежимЧто делаетЕсли файла нет
"r"чтение (режим по умолчанию)ошибка FileNotFoundError
"w"запись, старое содержимое стираетсяфайл создаётся
"a"дописывание в конецфайл создаётся
"r" чтение было стало файл не меняется если файла нет: FileNotFoundError "w" запись со стиранием было стало старое стёрто если файла нет: файл создаётся "a" дописывание в конец было стало новое — в конце если файла нет: файл создаётся
Режим "r" только читает файл, "w" при открытии стирает старое содержимое, "a" дописывает новое в конец; если файла нет, "r" даёт FileNotFoundError, а "w" и "a" создают файл.

Кодировка

Параметр encoding="utf-8" говорит, в какой кодировке хранить русские буквы. В Windows без него Python до версии 3.15 берёт кодировку системы (в русской Windows — cp1251), и файл, записанный на одном компьютере, может открыться «кракозябрами» на другом или не прочитаться вовсе. Указывайте encoding="utf-8" всегда — и при записи, и при чтении: так программа одинаково работает везде.

Чтение файла

Целиком файл читает read(), по строкам — цикл for по открытому файлу. Каждая строка приходит с \n на конце, его убирают методом strip():

Python
with open("cities.txt", "w", encoding="utf-8") as f:
    f.write("Минск\nБрест\nГродно\n")

with open("cities.txt", encoding="utf-8") as f:
    for line in f:
        print(line.strip())

with open("cities.txt", encoding="utf-8") as f:
    text = f.read()
print(len(text.split()))
Вывод
Минск
Брест
Гродно
3

Программа сначала создаёт файл, а потом читает его двумя способами. Режим "r" можно не писать — он по умолчанию.

Числа из файла

В файле всё — текст. Числа после чтения переводят через int или float, как после input:

Python
with open("marks.txt", "w", encoding="utf-8") as f:
    f.write("8\n9\n7\n10\n")

with open("marks.txt", encoding="utf-8") as f:
    marks = [int(line) for line in f]

print(marks)
print("Среднее:", sum(marks) / len(marks))

with open("result.txt", "w", encoding="utf-8") as f:
    f.write(f"Среднее: {sum(marks) / len(marks)}\n")
Вывод
[8, 9, 7, 10]
Среднее: 8.5

int сам отбрасывает пробелы и \n по краям строки, поэтому int(line) работает без strip. Но пустая строка в файле даст ошибку — о том, как с ней справиться, ниже.

Исключения

Когда при выполнении случается ошибка — деление на ноль, int("abc"), нет файла, — Python создаёт исключение. Если его не перехватить, программа останавливается и выводит сообщение. Перехватывают исключения конструкцией try … except:

Python
text = "abc"
try:
    n = int(text)
    print("Число:", n)
except ValueError:
    print("Это не число")
print("Программа работает дальше")
Вывод
Это не число
Программа работает дальше

Python выполняет блок try. Если в нём случилась ошибка указанного вида, остаток блока пропускается и выполняется блок except. Если ошибки нет, except пропускается.

text = "abc" text = "42" try: n = int(text) print("Число:", n) except ValueError: print("Это не число") print("Программа работает дальше") ValueError ошибка пропуск пропуск пропуск
При text = "abc" строка int(text) вызывает ValueError, остаток try пропускается и выполняется except; при "42" ошибки нет и пропускается except, а последняя строка выполняется всегда.

Частый случай — переспрашивать, пока не введут число:

Python
while True:
    try:
        n = int(input())
        break
    except ValueError:
        print("Нужно целое число, попробуйте ещё раз")
print("Квадрат:", n * n)
Ввод
пять
5
Вывод
Нужно целое число, попробуйте ещё раз
Квадрат: 25

Несколько видов ошибок

Для разных ошибок пишут несколько блоков except. Через as можно получить само исключение и вывести его текст:

Python
for b in [2, 0, "x"]:
    try:
        print(10 / b)
    except ZeroDivisionError:
        print("На ноль делить нельзя")
    except TypeError as e:
        print("Ошибка типа:", e)
Вывод
5.0
На ноль делить нельзя
Ошибка типа: unsupported operand type(s) for /: 'int' and 'str'

Отсутствующий файл — тоже исключение:

Python
try:
    with open("no_such_file.txt", encoding="utf-8") as f:
        print(f.read())
except FileNotFoundError:
    print("Файла нет")
Вывод
Файла нет
ИсключениеКогда бывает
ValueErrorзначение не подходит: int("abc")
TypeErrorдействие не для этого типа: "5" + 3
ZeroDivisionErrorделение на ноль
IndexErrorнет элемента с таким индексом
KeyErrorнет такого ключа в словаре
FileNotFoundErrorнет такого файла

else и finally

К try можно добавить блок else — он выполняется, если ошибки не было, — и finally, который выполняется всегда, была ошибка или нет:

Python
try:
    n = int("42")
except ValueError:
    print("Ошибка")
else:
    print("Прочитано:", n)
finally:
    print("Конец проверки")
Вывод
Прочитано: 42
Конец проверки

Чего не делать

Не пишите except: без названия ошибки и не перехватывайте всё подряд через except Exception, если не знаете зачем. Такой блок проглотит и опечатку в имени переменной, и любую другую ошибку — программа будет молча работать неправильно, и найти причину станет гораздо труднее. Перехватывайте те ошибки, которые ожидаете и знаете, как обработать.

Коротко

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

1. Что случится с содержимым файла, если открыть его в режиме "w"?
2. Зачем при открытии файла указывать encoding="utf-8"?
3. Что выведет программа?
Python
try:
    x = int("12a")
    print("A")
except ValueError:
    print("B")
print("C")
4. Какое исключение возникает при попытке открыть для чтения файл, которого нет?