📦 Репозиторий занятия 48

Урок 48. Исключения: обработка ошибок

Как работать с репозиторием

Каждая карточка говорит, о чём файл, что он выводит и что в нём искать. Код виден прямо здесь: его можно скопировать одной кнопкой, скачать файл или открыть его целиком.

Маршрут изучения

  1. Прочитайте описание: по нему уже понятно, о чём файл и что он выведет.
  2. Предскажите вывод: сравните своё предположение со строкой «Что выводит».
  3. Запустите: скачайте файл или скопируйте код кнопкой и выполните его у себя.
  4. Измените: поменяйте одно условие или значение и объясните новый результат.

Файлы: рекомендуемый порядок

1
PythonИсполняемый пример16 строк

Простейший логгер: basicConfig() с уровнем и файлом

less_25__exceptions__logging/theory_01_logging/a_simplest_logger/simplest_logger.py

Показывает минимальную настройку модуля logging через logging.basicConfig(): задаётся уровень INFO, формат сообщения и запись в файл simplest.log. Пять вызовов уровня разной важности демонстрируют, что DEBUG отфильтровывается порогом INFO, а всё от INFO и выше проходит. Отдельно в комментарии отмечено: если передать filename, вывод в консоль (stream) пропадает — работает только файл.

  • logging.basicConfig(level=logging.INFO, format=..., filename='simplest.log') — базовая настройка
  • logging.debug(...) — не выводится, т.к. ниже порога INFO
  • logging.info/warning/error/critical(...) — четыре сообщения проходят порог
  • if __name__ == "__main__": — код выполняется только при прямом запуске

Что выводит: Файл simplest.log получает 4 строки — INFO, WARNING, ERROR, CRITICAL с таймстампом и уровнем, например «2026-08-13 20:57:40,180 - INFO - Программа запущена»; сообщение DEBUG в файл не попадает, а в консоли ничего не печатается, т.к. вывод перенаправлен в filename.

Файл целиком (16 строк)
import logging

# Настройка базового логгера
logging.basicConfig(
    level=logging.INFO,                    # Уровень логирования
    format='%(asctime)s - %(levelname)s - %(message)s',  # Формат сообщения
    # можно добавить запись в файл, но при этом потерять вывод в stream:
    filename='simplest.log'
)

if __name__ == "__main__":
    logging.debug("Это сообщение уровня DEBUG (не выведется, т.к. уровень INFO)")
    logging.info("Программа запущена")
    logging.warning("Предупреждение!")
    logging.error("Ошибка!")
    logging.critical("Критическая ошибка!")
Проверьте себя: Что нужно изменить в basicConfig(), чтобы сообщения одновременно и писались в simplest.log, и выводились в консоль?
Открыть файл →
2
PythonКонфигурация25 строк

Root logger с двумя хендлерами: файл + консоль

less_25__exceptions__logging/theory_01_logging/root_logging/log_config.py

Настраивает корневой логгер через logging.basicConfig() с явным списком хендлеров — FileHandler пишет в app.log, StreamHandler выводит в stderr, у обоих общий Formatter с именем модуля и номером строки. force=True сбрасывает предыдущие настройки root logger, чтобы не задваивать сообщения при повторном импорте. Блок if __name__ == "__main__" содержит проверочные вызовы, которые срабатывают и при прямом запуске файла.

  • file_handler = logging.FileHandler("app.log", encoding="utf-8")
  • console_handler = logging.StreamHandler(sys.stderr)
  • formatter — общий формат с %(name)s, %(filename)s, %(lineno)d
  • logging.basicConfig(level=DEBUG, handlers=[...], force=True)
  • if __name__ == "__main__": — logging.info() и logging.error() проверяют оба хендлера

Что выводит: При прямом запуске (python log_config.py) в консоль и в app.log попадают две строки: «... [INFO] (root) module: log_config.py; line # 24: Сообщение INFO — попадёт и в файл, и в консоль» и аналогичная строка уровня ERROR.

Начало файла
import logging
import sys

# Создаём два хендлера
file_handler = logging.FileHandler("app.log", encoding="utf-8")
console_handler = logging.StreamHandler(sys.stderr)
# console_handler = logging.StreamHandler()  # Можно и без параметров

# Настраиваем формат
formatter = logging.Formatter("%(asctime)s [%(levelname)s] (%(name)s) module: %(filename)s; line # %(lineno)d: %(message)s")
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# Конфигурация root logger через basicConfig
Показать файл целиком (25 строк)
import logging
import sys

# Создаём два хендлера
file_handler = logging.FileHandler("app.log", encoding="utf-8")
console_handler = logging.StreamHandler(sys.stderr)
# console_handler = logging.StreamHandler()  # Можно и без параметров

# Настраиваем формат
formatter = logging.Formatter("%(asctime)s [%(levelname)s] (%(name)s) module: %(filename)s; line # %(lineno)d: %(message)s")
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# Конфигурация root logger через basicConfig
logging.basicConfig(
    level=logging.DEBUG,
    handlers=[file_handler, console_handler],
    force=True  # очищает старые хендлеры, чтобы не дублировались сообщения
)


if __name__ == "__main__":
    # Проверим
    logging.info("Сообщение INFO — попадёт и в файл, и в консоль")
    logging.error("Сообщение ERROR — тоже в оба места")
Проверьте себя: Зачем нужен параметр force=True в basicConfig() и что произойдёт, если его убрать при повторном импорте модуля?
Открыть файл →
3
PythonИсполняемый пример5 строк

Дочерний логгер наследует хендлеры root logger

less_25__exceptions__logging/theory_01_logging/root_logging/module_a.py

Показывает главную идею root-конфигурации: файл ничего не настраивает сам, а только импортирует log_config (что уже сконфигурировало root logger) и берёт логгер по имени модуля через logging.getLogger(__name__). Поскольку у дочернего логгера нет своих хендлеров, сообщение автоматически уходит туда же, куда и root — в app.log и консоль.

  • import log_config — побочный эффект: настраивает root logger при импорте
  • log = logging.getLogger(__name__) — дочерний логгер с именем __main__ при прямом запуске
  • log.info("Привет из модуля A!") — сообщение наследует формат и хендлеры root logger

Что выводит: При запуске «python module_a.py» из папки root_logging (со скопированным рядом log_config.py) в консоль и в app.log выводится одна строка: «... [INFO] (__main__) module: module_a.py; line # 5: Привет из модуля A!».

Файл целиком (5 строк)
import logging
import log_config

log = logging.getLogger(__name__)
log.info("Привет из модуля A!")
Проверьте себя: Что попадёт в поле %(name)s в логе, если module_a.py будет не запущен напрямую, а импортирован из другого файла?
Открыть файл →
4
MarkdownРазбор концепции91 строк

Конспект: базовый root logger — как это работает и таблица плюсов/минусов

less_25__exceptions__logging/theory_01_logging/root_logging/theory__root_logging.md

Пошагово объясняет, что происходит «под капотом» при импорте logging и вызове basicConfig(): создание root logger, двух хендлеров и форматтера, привязка форматтера к каждому хендлеру, финальная конфигурация с force=True. Отдельно описан механизм наследования: как дочерний логгер в другом файле получает те же хендлеры root logger без собственной настройки. Завершается таблицей плюсов и минусов подхода с одним общим root logger.

  • Шаги 1–5: создание root logger → хендлеры → formatter → привязка → basicConfig()
  • Пояснение полей формата: время, уровень, имя логгера, модуль, номер строки
  • Пример module_a.py — logging.getLogger(__name__) наследует хендлеры root
  • Примечание: параметр handlers как список появился в Python 3.8
  • Таблица «Плюсы / Минусы» по простоте, переиспользуемости, совместимости, управляемости, отладке, производительности
Показать начало файла (91 строк всего)
# Базовый root (корневой) логгер

## Пример

`log_config.py`

```python
import logging

# Создаём два хендлера
file_handler = logging.FileHandler("app.log", encoding="utf-8")
console_handler = logging.StreamHandler()

# Настраиваем формат
formatter = logging.Formatter("%(asctime)s [%(levelname)s] (%(name)s) module: %(filename)s; line # %(lineno)d: %(message)s")
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# Конфигурация root logger через basicConfig
logging.basicConfig(
    level=logging.DEBUG,
    handlers=[file_handler, console_handler],  # ← передаём сразу несколько
    force=True  # очищает старые хендлеры, чтобы не дублировались сообщения
)

# Проверим
logging.info("Сообщение INFO — попадёт и в файл, и в консоль")
logging.error("Сообщение ERROR — тоже в оба места")
```

---

## Что происходит "под капотом"?

1. При импорте `import logging` Python создаёт **root logger** — это объект `logging.getLogger()` без имени.
2. Далее создаются два обработчика (хэндлера): `file_handler` и `stream_handler`
3. Cоздаётся форматтер (`formatter`)для форматирования вывода, с параметрами:
   * дата события: `2026-06-15 09:25:22,255`
   * уровень логирования: `INFO`
   * имя логгера: `root`
   * имя модуля, из которого был вызван логгер: `log_config.py`
   * номер строки в этом файле, где был вызван метод логирования: `45`
4. Эти параметры форматтера далее добавляется к каждому хэндлеру.
5. Далее, при вызове метода `logging.basicConfig()`, к корневому логгеру будут добавлены:

   * два отформатированных обработчика,
   * задан минимальный уровень логирования
   * и сброшены все предыдущие возможные настройки корневого логгера (`force=True`)

После этого все вызовы `logging.info()`, `logging.debug()`, `logging.error()` и т.д.
будут обращаются именно к этому `root logger`.


ВАЖНО: возможность добавлять более одного хэндлера в `basicConfig()` появилась в версии Python3.8

---

## Как другие файлы используют тот же root logger?

В другом файле (например `module_a.py`, мы просто пишем:
…
Проверьте себя: Почему в таблице «Отладка» отсутствие разделения по контексту (например, для HTTP-запросов) отмечено как минус — какой подход из файла special_loggers эту проблему решает?
5
PythonИсполняемый пример5 строк

Именованный логгер 'db' — доступ к своей конфигурации по имени

less_25__exceptions__logging/theory_01_logging/special_loggers/database.py

Демонстрирует, что logging.getLogger("db") в любом файле возвращает один и тот же объект логгера, если он уже был настроен где-то ранее (в log_config.py) с этим именем. Файл сам не настраивает хендлеры — вся конфигурация приходит через import log_config. Сообщение уровня DEBUG проходит порог, заданный для db_logger.

  • import log_config — настраивает три именованных логгера, включая "db"
  • db_log = logging.getLogger("db") — берём именно тот логгер, что сконфигурирован под db.log
  • db_log.debug(...) — уровень DEBUG проходит, т.к. db_logger.setLevel(logging.DEBUG)

Что выводит: При запуске «python database.py» из скопированной папки special_loggers сообщение уходит ТОЛЬКО в файл db.log (у db_logger нет консольного хендлера), консоль остаётся пустой; строка в db.log: «... [DEBUG] (db): Запрос к базе данных выполнен».

Файл целиком (5 строк)
import logging
import log_config

db_log = logging.getLogger("db")
db_log.debug("Запрос к базе данных выполнен")
Проверьте себя: Почему сообщение db_log.debug() не появляется в консоли, хотя logging.info() из main.py там показывается?
Открыть файл →
6
PythonКонфигурация48 строк

Три независимых логгера в одном файле конфигурации

less_25__exceptions__logging/theory_01_logging/special_loggers/log_config.py

Настраивает три именованных логгера ('app', 'db', 'network') с разными уровнями и разными наборами хендлеров: у 'app' — файл main.log плюс консоль, у 'db' и 'network' — только собственные файлы. handlers.clear() перед добавлением хендлеров защищает от дублирования при повторном импорте. Блок if __name__ == "__main__" проверяет все три логгера сразу.

  • formatter — общий Formatter для всех трёх логгеров
  • app_logger (INFO) — FileHandler(main.log) + StreamHandler(stderr)
  • db_logger (DEBUG) — только FileHandler(db.log)
  • net_logger (WARNING) — только FileHandler(network.log)
  • handlers.clear() перед addHandler — защита от дублей при повторном импорте
  • if __name__ == "__main__": — по одному проверочному вызову на каждый логгер

Что выводит: При запуске «python log_config.py» напрямую в консоль печатается только одна строка от app_logger («... [INFO] (app): Сообщение из основного логгера»), т.к. только у него есть StreamHandler; db_logger и net_logger пишут свои строки только в db.log и network.log соответственно.

Начало файла
import logging
import sys

# --- Общий формат ---
formatter = logging.Formatter(
    "%(asctime)s [%(levelname)s] (%(name)s): %(message)s"
)

# --- Конфиг для основного приложения ("app") ---
file_handler_main = logging.FileHandler("main.log", encoding="utf-8")
file_handler_main.setFormatter(formatter)

console_handler = logging.StreamHandler(sys.stderr)
# console_handler = logging.StreamHandler()  # Можно и без параметров
Показать файл целиком (48 строк)
import logging
import sys

# --- Общий формат ---
formatter = logging.Formatter(
    "%(asctime)s [%(levelname)s] (%(name)s): %(message)s"
)

# --- Конфиг для основного приложения ("app") ---
file_handler_main = logging.FileHandler("main.log", encoding="utf-8")
file_handler_main.setFormatter(formatter)

console_handler = logging.StreamHandler(sys.stderr)
# console_handler = logging.StreamHandler()  # Можно и без параметров
console_handler.setFormatter(formatter)

app_logger = logging.getLogger("app")
app_logger.setLevel(logging.INFO)
app_logger.handlers.clear()
app_logger.addHandler(file_handler_main)
app_logger.addHandler(console_handler)


# --- Конфиг для базы данных ("db") ---
file_handler_db = logging.FileHandler("db.log", encoding="utf-8")
file_handler_db.setFormatter(formatter)

db_logger = logging.getLogger("db")
db_logger.setLevel(logging.DEBUG)
db_logger.handlers.clear()
db_logger.addHandler(file_handler_db)


# --- Конфиг для сетевых операций ("network")---
file_handler_net = logging.FileHandler("network.log", encoding="utf-8")
file_handler_net.setFormatter(formatter)

net_logger = logging.getLogger("network")
net_logger.setLevel(logging.WARNING)
net_logger.handlers.clear()
net_logger.addHandler(file_handler_net)


# Проверим
if __name__ == "__main__":
    app_logger.info("Сообщение из основного логгера")
    db_logger.debug("Сообщение из логгера базы данных")
    net_logger.error("Ошибка из сетевого логгера")
Проверьте себя: Почему в консоли при запуске log_config.py видно только сообщение от app_logger, а не от db_logger и net_logger?
Открыть файл →
7
PythonИсполняемый пример5 строк

Основной модуль приложения — использует логгер 'app'

less_25__exceptions__logging/theory_01_logging/special_loggers/main.py

Аналог module_a.py из root_logging, но для схемы с несколькими именованными логгерами: файл импортирует log_config (что настраивает все три логгера) и берёт логгер именно 'app' по строковому имени, а не по __name__. Так main.py гарантированно пишет в main.log и консоль, а не создаёт новый безымянный логгер.

  • import log_config — подключает конфигурацию всех трёх логгеров
  • log = logging.getLogger("app") — явное имя, а не __name__
  • log.info("Привет из основного модуля") — уходит в main.log и консоль

Что выводит: При запуске «python main.py» из скопированной папки special_loggers в консоль и в main.log выводится: «... [INFO] (app): Привет из основного модуля».

Файл целиком (5 строк)
import logging
import log_config  # ← подключает все логгеры

log = logging.getLogger("app")
log.info("Привет из основного модуля")
Проверьте себя: Что изменится в поведении main.py, если заменить logging.getLogger("app") на logging.getLogger(__name__)?
Открыть файл →
8
PythonИсполняемый пример5 строк

Именованный логгер 'network' — только файловый вывод, порог WARNING

less_25__exceptions__logging/theory_01_logging/special_loggers/network.py

Симметричен database.py, но для логгера 'network': net_logger настроен с уровнем WARNING и единственным FileHandler на network.log. Сообщение уровня WARNING проходит порог и попадает в файл, консоли у этого логгера нет вообще.

  • import log_config — настраивает net_logger
  • net_log = logging.getLogger("network") — тот же объект, что сконфигурирован в log_config
  • net_log.warning(...) — WARNING проходит порог net_logger

Что выводит: При запуске «python network.py» из скопированной папки консоль остаётся пустой, а в network.log появляется строка: «... [WARNING] (network): Проблема с подключением».

Файл целиком (5 строк)
import logging
import log_config

net_log = logging.getLogger("network")
net_log.warning("Проблема с подключением")
Проверьте себя: Если вызвать net_log.info(...) вместо net_log.warning(...), появится ли сообщение в network.log — и почему?
Открыть файл →
9
MarkdownРазбор концепции115 строк

Конспект: несколько конфигураторов логов для разных частей приложения

less_25__exceptions__logging/theory_01_logging/special_loggers/theory__special_loggers.md

Показывает более гибкую схему логирования, чем единый root logger: каждая часть приложения ('app', 'db', 'network') получает собственный именованный логгер со своим уровнем и файлом через logging.getLogger(<имя>). Объясняет, что в других файлах достаточно запросить логгер по тому же имени, чтобы получить готовую конфигурацию. Завершается сравнительной таблицей плюсов и минусов подхода с несколькими логгерами.

  • Полный код log_config.py с тремя логгерами (app/db/network)
  • Примеры использования в main.py, database.py, network.py — getLogger(<имя>)
  • Пояснение: каждый логгер пишет в свой файл, с общим форматтером
  • Таблица «Плюсы / Минусы»: простота и раздельные файлы против громоздкости при росте числа логгеров
Показать начало файла (115 строк всего)
# Пример: несколько конфигураторов для разных частей приложения

## `log_config.py`

```python
import logging

# --- Общий формат ---
formatter = logging.Formatter(
    "%(asctime)s [%(levelname)s] (%(name)s): %(message)s"
)

# --- Конфиг для основного приложения ("app") ---
file_handler_main = logging.FileHandler("main.log", encoding="utf-8")
file_handler_main.setFormatter(formatter)

console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)

app_logger = logging.getLogger("app")
app_logger.setLevel(logging.INFO)
app_logger.handlers.clear()
app_logger.addHandler(file_handler_main)
app_logger.addHandler(console_handler)


# --- Конфиг для базы данных ("db") ---
file_handler_db = logging.FileHandler("db.log", encoding="utf-8")
file_handler_db.setFormatter(formatter)

db_logger = logging.getLogger("db")
db_logger.setLevel(logging.DEBUG)
db_logger.handlers.clear()
db_logger.addHandler(file_handler_db)


# --- Конфиг для сетевых операций ("network")---
file_handler_net = logging.FileHandler("network.log", encoding="utf-8")
file_handler_net.setFormatter(formatter)

net_logger = logging.getLogger("network")
net_logger.setLevel(logging.WARNING)
net_logger.handlers.clear()
net_logger.addHandler(file_handler_net)


# Проверим
if __name__ == "__main__":
    app_logger.info("Сообщение из основного логгера")
    db_logger.debug("Сообщение из логгера базы данных")
    net_logger.error("Ошибка из сетевого логгера")
```

---

## Как использовать в других модулях

`main.py`

```python
…
Проверьте себя: Чем идея именованных логгеров ('app', 'db', 'network') отличается от использования root logger из предыдущего файла — и в каком случае оправдан переход на неё?
10
PythonИсполняемый пример97 строк

try/except/finally: перехват нескольких типов исключений подряд

less_25__exceptions__logging/theory_02_try_except_finally.py

Демонстрирует классическую структуру обработки исключений с несколькими блоками except, идущими от конкретного типа (ValueError, ZeroDivisionError) к общему (Exception), и с finally, который выполняется всегда — и при исключении, и без него. В докстринге приведена полная иерархия встроенных исключений Python (от BaseException) как справочный материал.

  • Докстринг — полное дерево иерархии исключений BaseException → Exception → ...
  • x = int(input(...)) — потенциальный источник ValueError
  • result = 10 / x — потенциальный источник ZeroDivisionError
  • except ValueError / except ZeroDivisionError / except Exception — по убыванию конкретности
  • finally: print("Завершение программы.") — выполняется в любом случае

Что выводит: Ввод «abc» → «Ошибка! Введено не число: invalid literal for int() with base 10: 'abc'», затем «Завершение программы.»; ввод «0» → «Ошибка! Деление на ноль.: division by zero», затем «Завершение программы.»; ввод «5» → «Результат: 2.0», затем «Завершение программы.».

Начало файла
"""
https://hyperskill.org/learn/step/11680

Иерархия исключений:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- BaseExceptionGroup
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
Показать файл целиком (97 строк)
"""
https://hyperskill.org/learn/step/11680

Иерархия исключений:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- BaseExceptionGroup
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ExceptionGroup [BaseExceptionGroup]
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- EncodingWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning
"""


try:
    # Код, в котором может произойти исключение
    x = int(input("Введите число: "))
    result = 10 / x
    print("Результат:", result)

except ValueError as e:
    # Обработка исключения, когда введено не число
    print(f"Ошибка! Введено не число: {e}")

except ZeroDivisionError as e:
    # Обработка исключения деления на ноль
    print(f"Ошибка! Деление на ноль.: {e}")

except Exception as e:
    # Обработка других исключений
    print("Произошла ошибка:", e)

finally:
    # Код, который выполняется всегда, независимо от того, произошло исключение или нет
    print("Завершение программы.")

Проверьте себя: Что произойдёт, если поменять местами except ValueError и except Exception — почему порядок блоков except важен?
Открыть файл →
11
PythonИсполняемый пример15 строк

try/except/else/finally: блок else срабатывает только без ошибок

less_25__exceptions__logging/theory_03_try_except_else_finally.py

Расширяет предыдущий пример блоком else, который печатается ТОЛЬКО если в try не было исключения, — в отличие от finally, который выполняется всегда. Комментарий внутри f-строки else прямо объясняет разницу между else и finally, что снимает частую путаницу у новичков.

  • try: y = 10 / int(input(...)) — та же схема деления
  • except ValueError / except ZeroDivisionError / except Exception as e
  • else: print(f"Результат: {y}...") — только при отсутствии исключения
  • finally: print(...) — безусловно, после else или except

Что выводит: Ввод «4» → «Результат: 2.5» и пояснение про else, затем «Содержимое блока finally печатается в любом случае»; ввод «0» → «Ошибка деления на ноль» (блок else пропускается), затем та же строка finally.

Файл целиком (15 строк)
try:
    y = 10 / int(input("Введите число: "))
except ValueError:
    print("Ошибка! Вероятно вы ввели не число.")
except ZeroDivisionError:
    print("Ошибка деления на ноль")
except Exception as e:
    print(e)
else:
    print(f"Результат: {y}\n"
          f"(Содержимое блока else печатается, ТОЛЬКО если нет ошибки в блоке try.\n"
          f"И НЕ печатается, если ошибка есть)")
finally:
    print("Содержимое блока finally печатается в любом случае")
Проверьте себя: Почему при вводе «0» в консоли не появляется текст из блока else, хотя finally всё равно печатается?
Открыть файл →
12
PythonИсполняемый пример15 строк

raise: искусственно поднимаем исключение до того, как оно возникнет само

less_25__exceptions__logging/theory_04__raise.py

Показывает оператор raise — деление на ноль перехватывается вручную ДО фактической операции деления, ещё на этапе проверки if divisor == 0, с собственным текстом сообщения. Это иллюстрирует разницу между исключением, которое бросает сам интерпретатор (десять делится на ноль автоматически), и исключением, которое разработчик поднимает сознательно для контроля потока программы.

  • dividend = 100 — фиксированное делимое
  • divisor = int(input(...)) — потенциальный ValueError
  • if divisor == 0: raise ZeroDivisionError("...") — исключение поднимается вручную
  • result = dividend / divisor — выполняется, только если divisor != 0
  • except ValueError / except ZeroDivisionError — ловят оба случая

Что выводит: Ввод «0» → «Ошибка: Деление на ноль запрещено!» (собственный текст из raise, а не сообщение интерпретатора); ввод «5» → «Результат: 20.0».

Файл целиком (15 строк)
dividend = 100

try:
    divisor = int(input("Введите делитель: "))
    if divisor == 0:
        raise ZeroDivisionError("Ошибка: Деление на ноль запрещено!")

    result = dividend / divisor
    print(f"Результат: {result}")

except ValueError as e:
    print(f"{e}")

except ZeroDivisionError as e:
    print(e)
Проверьте себя: Чем сообщение об ошибке при вводе «0» в этом файле отличается от сообщения в theory_02, где ZeroDivisionError возникает сам по себе при делении?
Открыть файл →