Вспомните: в главе 1 перед открытием файла вы проверяли path.exists(), чтобы программа не упала на отсутствующем файле. Но файл может быть на месте и всё равно не прочитаться: кодировка не та, в ячейке суммы вместо числа — «сто», человек ввёл пустую строку. Тогда программа обрывалась на полуслове с красным текстом ошибки. В этом уроке учим её переживать такие случаи.
🎯 После урока сможете: прочитать текст ошибки и найти её тип, перехватить конкретную ошибку через try/except, пропустить битую строку таблицы и продолжить работу, выполнить код только при успехе (else) и всегда (finally), а в своей функции остановить работу с понятным сообщением через raise.
Что такое исключение и как читать текст ошибки
Когда Python не может выполнить строку, он создаёт исключение — объект с типом ошибки и сообщением — и останавливает программу. На экран выводится отчёт (его называют traceback): где упало и почему. Читать его надо снизу вверх: последняя строка — тип и сообщение, строки выше — путь к месту ошибки.
summa = int("12,5")
Вывод:
Traceback (most recent call last):
File "rashody.py", line 1, in <module>
summa = int("12,5")
ValueError: invalid literal for int() with base 10: '12,5'
Здесь тип — ValueError (значение не подходит: строку с запятой нельзя превратить в целое), сообщение — после двоеточия. Типы, которые встретятся в работе с файлами и вводом чаще всего:
ValueError— значение неподходящее:int("сто"),int(""),float("12р");FileNotFoundError— файла нет:open("nety.txt");UnicodeDecodeError— байты не читаются в указанной кодировке: файл в cp1251 открыли как utf-8;ZeroDivisionError— деление на ноль;KeyError— нет такого ключа в словаре:settings["шрифт"], а ключа нет;IndexError— нет элемента с таким номером в списке.

Проверьте себя
Задание. Какой тип ошибки выдаст программа? Введите имя исключения, как оно написано в последней строке отчёта.
Исходный код для этого задания:
amount = "сто" total = 450 + int(amount) print(total)Подсказка: Что не так: строка, которую превращают в число, или сама операция сложения?
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Файла otchet_sentyabr.txt в папке нет. Какой тип ошибки выдаст программа?
Исходный код для этого задания:
with open("otchet_sentyabr.txt", encoding="utf-8") as f: text = f.read()Подсказка: Откройте список частых ошибок в начале урока: какая из них относится к открытию файла, которого нет?
Онлайн-проверка ответа появится позже
try/except: перехватываем конкретную ошибку
Опасный код кладут в блок try, а в except пишут, что делать, если случилась ошибка указанного типа. Программа не падает, а идёт дальше. Главный приём для таблицы расходов — пропустить битую ячейку и считать остальное:
sums = ["450", "380", "сто", "620"]
total = 0
for s in sums:
try:
total += int(s)
except ValueError:
print("Не число, пропускаю:", s)
print("Итого:", total)
Вывод:
Не число, пропускаю: сто
Итого: 1450
Строка total += int(s) для «сто» не выполнилась: Python прыгнул в except, напечатал сообщение и перешёл к следующему элементу цикла.
Чтобы увидеть текст самой ошибки, дайте ей имя через as: внутри except переменная e хранит исключение, а print(e) печатает его сообщение.
settings = {"тема": "тёмная"}
try:
size = settings["шрифт"]
except KeyError as e:
print("В настройках нет ключа", e)
size = 12
print("Шрифт:", size)
Вывод:
В настройках нет ключа 'шрифт'
Шрифт: 12
Пишите в
exceptконкретный тип. Голыйexcept:илиexcept Exception:ловит всё подряд, включая опечатку в имени переменной, — и программа молча делает не то, а вы не узнаете почему.
Проверьте себя
Задание. Что программа напечатает последней строкой? Введите число. Обратите внимание: в «3OO» — буквы O, а не нули.
Исходный код для этого задания:
total = 0 for s in ["1200", "", "350", "3OO", "150"]: try: total += int(s) except ValueError: print("пропуск") print(total)Подсказка: Пройдите список по одному элементу: какие строки int() превращает в число, а какие уходят в except?
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Задание. Файл zametki.txt в папке есть, но сохранён в старом Блокноте в кодировке cp1251. Программа должна в этом случае перечитать его в cp1251, а вместо этого падает. Какой точный тип ошибки стоит в последней строке отчёта при падении? Его и нужно написать в except вместо KeyError. Введите имя исключения.
Исходный код для этого задания:
from pathlib import Path path = Path("zametki.txt") try: text = path.read_text(encoding="utf-8") except KeyError: text = path.read_text(encoding="cp1251") print("Символов:", len(text))Подсказка: Файл на месте, значит дело не в его отсутствии. Что не получается при чтении: байты или ключ словаря? Сверьтесь со списком частых ошибок урока.
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Несколько except: разная реакция на разные ошибки
После одного try можно поставить несколько except. Python проверяет их сверху вниз и выполняет первый подходящий. Пример — делим счёт на компанию: строка вида «сумма/человек».
def share(line):
total, people = line.split("/")
try:
return int(total) // int(people)
except ValueError:
print("Не число:", line)
return 0
except ZeroDivisionError:
print("Некому платить:", line)
return 0
print(share("3000/4"))
print(share("3000/0"))
print(share("три/2"))
Вывод:
750
Некому платить: 3000/0
0
Не число: три/2
0
Если реакция на разные ошибки одинаковая, перечислите типы в скобках: except (ValueError, KeyError):.
rows = [{"сумма": "450"}, {"итог": "300"}, {"сумма": "12р"}, {"сумма": "80"}]
total = 0
bad = 0
for row in rows:
try:
total += int(row["сумма"])
except (ValueError, KeyError):
bad += 1
print(total, bad)
Вывод:
530 2
Порядок важен. Если первым стоит
except Exception, он перехватит иValueError, иZeroDivisionError, и до более точных веток дело не дойдёт. Точные типы — выше, общий — в самом низу или не нужен вовсе.
Проверьте себя
Задание. Что выведет программа? Введите число.
Исходный код для этого задания:
def share(line): total, people = line.split("/") try: return int(total) // int(people) except ValueError: return -1 except ZeroDivisionError: return 0 result = 0 for line in ["1000/4", "900/0", "x/3", "600/3"]: result += share(line) print(result)Подсказка: Посчитайте share() для каждой строки отдельно: какая ветка сработает — обычный return, except ValueError или except ZeroDivisionError? Потом сложите.
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Что выведет программа?
Исходный код для этого задания:
try: n = int("двадцать") except Exception: print("Что-то пошло не так") except ValueError: print("Введите число цифрами")Подсказка: Ветки except проверяются сверху вниз, выполняется первая подходящая. Подходит ли ValueError под Exception?
Онлайн-проверка ответа появится позже
Задание. Сколько позиций заказа программа посчитает проблемными? Введите число, которое она выведет.
Исходный код для этого задания:
prices = {"хлеб": "60", "сыр": "сто", "чай": "250"} order = ["хлеб", "сыр", "кофе", "чай"] bad = 0 for item in order: try: int(prices[item]) except (ValueError, KeyError): bad += 1 print(bad)Подсказка: Для каждой позиции спросите: есть ли такой ключ в словаре? если есть — превращается ли значение в число?
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
else и finally: при успехе и всегда
У try есть ещё две необязательные ветки:
else— выполняется, только если вtryошибки не было. Сюда кладут работу с результатом: так вtryостаётся лишь опасная строка, и вы не перехватите чужую ошибку по случайности;finally— выполняется всегда: была ошибка или нет. Для завершающих действий: закрыть, записать в журнал, сообщить «готово».
for s in ["7", "x"]:
try:
n = int(s)
except ValueError:
print(s, "- не число")
else:
print(s, "- число, удвоим:", n * 2)
finally:
print(s, "- проверено")
Вывод:
7 - число, удвоим: 14
7 - проверено
x - не число
x - проверено
Для «7» сработали else и finally, для «x» — except и finally. Файлы, открытые через with, закрываются сами; finally нужен для остального — счётчиков, журнала, итогового сообщения.

Проверьте себя
Задание. Что выведет программа? Введите строку из латинских букв O, E и F без пробелов, в верхнем регистре.
Исходный код для этого задания:
for s in ["7", "x", "12"]: try: n = int(s) except ValueError: print("E", end="") else: print("O", end="") finally: print("F", end="")Подсказка: print(…, end=»») печатает без перехода на новую строку. Для каждого s решите: какая ветка — except или else — и выполняется ли finally.
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Программа читает число из строки через int(), а затем делает с числом длинные расчёты. Куда положить расчёты, чтобы они выполнялись только при удачном int() и чтобы ошибки внутри расчётов не перехватывались тем же except ValueError?
Подсказка: Какая ветка выполняется только тогда, когда в try не было исключения?
Онлайн-проверка ответа появится позже
raise: останавливаем работу с понятным сообщением
Иногда Python ошибки не видит, а для вашей задачи данные неверные: сумма расхода отрицательная, дата из будущего. Тогда исключение создают сами командой raise и пишут в сообщение, что именно не так:
def check_amount(amount):
if amount <= 0:
raise ValueError(f"сумма должна быть больше нуля, а пришло {amount}")
return amount
print(check_amount(450))
try:
check_amount(-300)
except ValueError as e:
print("Ошибка:", e)
Вывод:
450
Ошибка: сумма должна быть больше нуля, а пришло -300
raise прерывает функцию сразу: return после него не выполняется. Исключение уходит к тому, кто функцию вызвал, и дальше вверх — пока его не поймает except или программа не упадёт с вашим сообщением. Тип берите подходящий по смыслу: неверное значение — ValueError, нет файла — FileNotFoundError.
Удобный приём — проверить всё в одной функции-разборщике и ловить одну ошибку снаружи:
def parse_amount(text):
text = text.strip().replace(",", ".")
amount = float(text)
if amount <= 0:
raise ValueError(f"не положительная сумма: {text}")
return amount
for s in ["250,50", " 99 ", "-40", "бесплатно"]:
try:
print(parse_amount(s))
except ValueError as e:
print("Пропуск:", e)
Вывод:
250.5
99.0
Пропуск: не положительная сумма: -40
Пропуск: could not convert string to float: 'бесплатно'
Обратите внимание: ошибку float("бесплатно") Python создал сам, а ошибку для «-40» — ваш raise. Снаружи оба случая ловит один except ValueError.

Проверьте себя
Задание. Что выведет программа? Введите строку вывода целиком.
Исходный код для этого задания:
def check_amount(amount): if amount <= 0: raise ValueError(f"сумма должна быть больше нуля, а пришло {amount}") return amount try: check_amount(0) except ValueError as e: print("Ошибка:", e)Подсказка: Проходит ли 0 проверку amount <= 0? Если raise сработал, print(e) печатает текст, который передали в ValueError(…).
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Задание. Допишите пропуск: функция должна прервать работу с сообщением, если размер шрифта вне диапазона. Введите одно слово, которое стоит на месте ____.
Исходный код для этого задания:
def set_font(size): if size < 8 or size > 72: ____ ValueError("размер шрифта от 8 до 72") return sizeПодсказка: Какой командой в Python создают своё исключение?
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Задание. Что выведет программа? Введите два числа через пробел, как в выводе.
Исходный код для этого задания:
def parse_amount(text): text = text.strip().replace(",", ".") amount = float(text) if amount <= 0: raise ValueError("не положительная сумма") return amount total = 0 skipped = 0 for s in ["120,5", "-15", "0", " 80 ", "12р", "9,5"]: try: total += parse_amount(s) except ValueError: skipped += 1 print(total, skipped)Подсказка: Для каждой строки: что сделают strip и replace, превратит ли float её в число, пропустит ли проверка amount <= 0. Сложите только прошедшие.
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Надёжное чтение файлов и ввода
Соберём приёмы для двух частых случаев из главы 1. Первый — файл, про который неизвестно, в какой он кодировке. Пробуем utf-8, при UnicodeDecodeError — cp1251 (старые файлы Windows):
def read_any(data):
try:
return data.decode("utf-8"), "utf-8"
except UnicodeDecodeError:
return data.decode("cp1251"), "cp1251"
print(read_any("Отчёт".encode("utf-8")))
print(read_any("Отчёт".encode("cp1251")))
Вывод:
('Отчёт', 'utf-8')
('Отчёт', 'cp1251')
С файлом на диске то же самое: в try — path.read_text(encoding="utf-8"), в except UnicodeDecodeError — повтор с encoding="cp1251", а отдельный except FileNotFoundError заменяет прежнюю проверку exists().
from pathlib import Path
def read_text_file(path):
try:
return path.read_text(encoding="utf-8")
except UnicodeDecodeError:
return path.read_text(encoding="cp1251")
except FileNotFoundError:
print("Нет файла:", path.name)
return ""
text = read_text_file(Path("zametki.txt"))
Второй — ввод с клавиатуры. Человек может ввести что угодно, поэтому спрашиваем в цикле, пока ответ не подойдёт. break стоит в else: из цикла выходим только при удачном разборе.
while True:
answer = input("Сколько потратили? ")
try:
amount = int(answer)
if amount <= 0:
raise ValueError("нужно число больше нуля")
except ValueError as e:
print("Не подходит:", e)
else:
break
print("Записал:", amount)
Пример диалога (ввод человека — после вопроса):
Сколько потратили? сто
Не подходит: invalid literal for int() with base 10: 'сто'
Сколько потратили? -50
Не подходит: нужно число больше нуля
Сколько потратили? 450
Записал: 450
Сохраните функцию
read_text_fileу себя и откройте ею старый текстовый файл, созданный в Блокноте Windows, и новый — созданный в VS Code. Посмотрите, в какую ветку ушёл каждый.
Проверьте себя
Задание. Что выведет программа? Введите название кодировки, как в выводе.
Исходный код для этого задания:
data = "Привет".encode("cp1251") try: text = data.decode("utf-8") enc = "utf-8" except UnicodeDecodeError: text = data.decode("cp1251") enc = "cp1251" print(enc)Подсказка: Байты получены в одной кодировке, а читаем сначала в другой. Получится ли это, и какая ветка выполнится?
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Задание. Список answers имитирует то, что человек по очереди вводит в программу. Что выведет программа? Введите два числа через пробел, как в выводе.
Исходный код для этого задания:
answers = ["", "двадцать", "-5", "250", "300"] attempts = 0 for a in answers: attempts += 1 try: n = int(a) if n <= 0: raise ValueError("нужно больше нуля") except ValueError: continue else: break print(attempts, n)Подсказка: Идите по списку и после каждого ответа отмечайте: значение attempts, значение n, какая ветка сработала. Помните: n присваивается до проверки на ноль.
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Задание. Проектная миссия «Грязная выгрузка расходов». Выгрузка чеков заполнялась руками, в ней попадаются пустые суммы, слова вместо чисел, отрицательные суммы, строки без разделителя, дробная часть через запятую. Напишите утилиту: читает файл rashody_gryaz.txt (utf-8, данные целиком ниже, 52 строки «статья;сумма»), разбирает каждую строку через line.split(«;») и свою функцию parse_amount(text) — она меняет запятую на точку, превращает текст в float и через raise ValueError отбраковывает сумму ≤ 0. Плохие строки программа не роняет, а пропускает и считает. В конце печатает общую сумму хороших строк, округлённую round() до целого, и число пропущенных. Проверьте и на своей выгрузке. В поле ответа — общая сумма для данных из условия. Приложите файл программы .py; в поле ответа — число.
Принято, если:
1. введённое число совпадает с эталоном;
2. приложен файл .py, который это число выдаёт на данных из условия;Самопроверка перед сдачей (преподаватель смотрит на занятии):
3. в except указан конкретный тип, а не голый except;
4. отрицательная сумма отбраковывается вашим raise с понятным сообщением.Связь;960,86
Аптека;2969
Одежда;140
Еда;1183
Связь;2443
Связь;
Связь;776
Кино;364
Связь;314
Связь;1045
Еда;1871
Кино;461
Такси;2584
Кино;1151
Аптека;1755
Кино;788,04
Связь;бесплатно
Аптека;2218
Аптека;832
Аптека;1445
Такси;0
Кино;1834
Связь;1360
Связь;2307
Аптека;420,05
Аптека
Аптека;1739
Одежда;231
Аптека;0
Аптека;
Одежда;216,85
Еда;1594,73
Связь
Аптека;2944,74
Одежда;0
Одежда;1472
Еда;1108
Еда;1977
Кино;1549
Кино;835
Связь;500
Еда;1122
Кино;2455
Еда;2721,22
Аптека;297
Связь;386
Связь;714
Аптека;0
Кино;12р
Еда;2340
Еда;751
Связь;1760
Подсказка: Строка без «;» тоже даёт ValueError при распаковке cat, s = line.split(«;») — поэтому split можно держать внутри того же try.
✅ Готово, если: ответ раскрывает то, что просит критерий приёмки в задании выше.
Онлайн-проверка ответа появится позже
Задание. Проектная миссия «Делим счета». Друзья ведут журнал общих счетов: строка «кто платил;сумма;на сколько человек». Журнал ниже целиком (48 строк, файл scheta.txt, utf-8). Напишите утилиту: для каждой строки считает долю одного человека int(сумма) // int(человек) и складывает доли. Строки с нулём человек и строки с нечисловой суммой или числом людей программа не роняет, а считает отдельно — двумя разными except, у каждого свой счётчик. В конце печатает сумму долей и оба счётчика. В поле ответа — сумма долей для данных из условия. Приложите файл программы .py; в поле ответа — число.
Принято, если:
1. введённое число совпадает с эталоном;
2. приложен файл .py, который это число выдаёт на данных из условия;Самопроверка перед сдачей (преподаватель смотрит на занятии):
3. ZeroDivisionError и ValueError обрабатываются в разных except;
4. программа печатает, сколько строк попало в каждую группу.Кира;4800;4
Жанна;8500;4
Вера;15к;6
Кира;6400;7
Кира;;2
Борис;6700;6
Егор;тысяча;3
Кира;5800;0
Жанна;6100;1
Кира;5100;7
Вера;2500;
Илья;5900;0
Илья;2600;6
Лев;2300;3
Кира;7000;7
Лев;4000;3
Глеб;;4
Жанна;4900;1
Жанна;6000;2
Дина;5800;
Дина;тысяча;3
Кира;1800;6
Борис;15к;5
Анна;4600;8
Кира;7300;2
Лев;7800;4
Кира;;3
Борис;15к;3
Жанна;8400;1
Вера;1900;6
Дина;8100;7
Глеб;6800;4
Кира;800;6
Вера;3500;4
Глеб;6600;6
Борис;8500;8
Глеб;8200;0
Анна;тысяча;3
Лев;8600;2
Кира;8100;5
Кира;4700;0
Кира;4500;1
Вера;5900;8
Дина;7500;2
Илья;2800;8
Глеб;8200;2
Дина;1800;5
Илья;7900;2
Подсказка: Разбейте строку через split(«;»), деление положите в try, после него — except ZeroDivisionError и except ValueError, каждый увеличивает свой счётчик.
✅ Готово, если: ответ раскрывает то, что просит критерий приёмки в задании выше.
Онлайн-проверка ответа появится позже
Что дальше
Теперь вы умеете читать текст ошибки снизу вверх, перехватывать конкретные исключения через try/except, пропускать битые строки таблицы, разделять успех и завершение через else и finally и останавливать свою функцию понятным сообщением через raise. В следующем уроке займёмся датами: научим программу считать сроки, разницу между днями и переводить дату из текста в объект и обратно — и там же пригодится try, когда дата записана с ошибкой.
← Назад · ↑ В начало урока · ⌂ К навигатору курса · Вперёд →
