Урок 10. Файлы и исключения
Всё, что программа хранит в переменных, пропадает, как только она закончила работу. Чтобы данные сохранились, их записывают в файл. А чтобы программа не падала от неверного ввода или отсутствующего файла, ошибки перехватывают — это исключения. Обе темы в этом уроке.
Запись в файл
Файл открывают функцией open — с именем файла и режимом: "w" — запись. Удобнее всего — внутри with: когда блок закончится, файл закроется сам, даже если в блоке случилась ошибка.
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("Первая строка\n")
f.write("Вторая строка\n")
print("Файл записан")Файл записанf— имя, под которым открытый файл доступен внутри блока;writeпишет строку как есть — перевод строки\nнужно добавлять явно;writeпринимает только строки: число сначала переводят черезstrили f-строку.
Файл notes.txt появится в текущей папке — обычно это папка, из которой запущена программа. Подробнее о том, где ищется файл, — в справке Как прочитать и записать файл.
Режим "w" стирает всё, что было в файле, ещё при открытии. Если файл с таким именем уже есть, его старое содержимое пропадёт без предупреждения. Чтобы дописать в конец, откройте файл в режиме "a".
Режимы открытия
| Режим | Что делает | Если файла нет |
|---|---|---|
"r" | чтение (режим по умолчанию) | ошибка FileNotFoundError |
"w" | запись, старое содержимое стирается | файл создаётся |
"a" | дописывание в конец | файл создаётся |
Кодировка
Параметр encoding="utf-8" говорит, в какой кодировке хранить русские буквы. В Windows без него Python до версии 3.15 берёт кодировку системы (в русской Windows — cp1251), и файл, записанный на одном компьютере, может открыться «кракозябрами» на другом или не прочитаться вовсе. Указывайте encoding="utf-8" всегда — и при записи, и при чтении: так программа одинаково работает везде.
Чтение файла
Целиком файл читает read(), по строкам — цикл for по открытому файлу. Каждая строка приходит с \n на конце, его убирают методом strip():
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:
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.5int сам отбрасывает пробелы и \n по краям строки, поэтому int(line) работает без strip. Но пустая строка в файле даст ошибку — о том, как с ней справиться, ниже.
Исключения
Когда при выполнении случается ошибка — деление на ноль, int("abc"), нет файла, — Python создаёт исключение. Если его не перехватить, программа останавливается и выводит сообщение. Перехватывают исключения конструкцией try … except:
text = "abc"
try:
n = int(text)
print("Число:", n)
except ValueError:
print("Это не число")
print("Программа работает дальше")Это не число
Программа работает дальшеPython выполняет блок try. Если в нём случилась ошибка указанного вида, остаток блока пропускается и выполняется блок except. Если ошибки нет, except пропускается.
Частый случай — переспрашивать, пока не введут число:
while True:
try:
n = int(input())
break
except ValueError:
print("Нужно целое число, попробуйте ещё раз")
print("Квадрат:", n * n)пять
5Нужно целое число, попробуйте ещё раз
Квадрат: 25Несколько видов ошибок
Для разных ошибок пишут несколько блоков except. Через as можно получить само исключение и вывести его текст:
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'Отсутствующий файл — тоже исключение:
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, который выполняется всегда, была ошибка или нет:
try:
n = int("42")
except ValueError:
print("Ошибка")
else:
print("Прочитано:", n)
finally:
print("Конец проверки")Прочитано: 42
Конец проверкиЧего не делать
Не пишите except: без названия ошибки и не перехватывайте всё подряд через except Exception, если не знаете зачем. Такой блок проглотит и опечатку в имени переменной, и любую другую ошибку — программа будет молча работать неправильно, и найти причину станет гораздо труднее. Перехватывайте те ошибки, которые ожидаете и знаете, как обработать.
Коротко
- Файл открывают
with open(имя, режим, encoding="utf-8") as f:— закроется сам. "r"— чтение,"w"— запись со стиранием,"a"— дописывание.f.write(строка)— запись,f.read()— весь текст,for line in f— по строкам,strip()убирает\n.- Ошибка при работе — исключение;
try…except ВидОшибки:перехватывает его. - Перехватывайте конкретные ошибки:
ValueError,FileNotFoundError,ZeroDivisionError.