Содержание

Мир Python: исключения | Python для продвинутых

Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Введение

В этом уроке вы узнаете о важном средстве языка, без которого крупная программа не может обойтись. Речь пойдет об исключениях. Что это такое, как ими пользоваться и как создавать собственные?

Исключительные ситуации или исключения (exceptions) – это ошибки, обнаруженные при исполнении. Например, к чему приведет попытка чтения несуществующего файла? Или если файл был случайно удален пока программа работала? Такие ситуации обрабатываются при помощи исключений.

Если же Python не может понять, как обойти сложившуюся ситуацию, то ему не остается ничего кроме как поднять руки и сообщить, что обнаружил ошибку. В общем, исключения необходимы, чтобы сообщать программисту об ошибках.

Простейший пример исключения — деление на ноль:

>>> 100 / 0
Traceback (most recent call last):
  File "", line 1, in
    100 / 0
ZeroDivisionError: division by zero

В данном случае интерпретатор сообщил нам об исключении ZeroDivisionError – делении на ноль.

Traceback

В большой программе исключения часто возникают внутри. Чтобы упростить программисту понимание ошибки и причины такого поведения Python предлагает Traceback или в сленге – трэйс. Каждое исключение содержит краткую информацию, но при этом полную, информацию о месте появления ошибки. По трэйсу найти и исправить ошибку становится проще.

Рассмотрим такой пример:

Traceback (most recent call last):
  File "/home/username/Develop/test/app.py", line 862, in _handle
    return route.call(**args)
  File "/home/username/Develop/test/app.py", line 1729, in wrapper
    rv = callback(*a, **ka)
  File "/home/username/Develop/test/__init__.py", line 76, in wrapper
    body = callback(*args, **kwargs)
  File "/home/username/Develop/test/my_app.py", line 16, in index
    raise Exception('test exception')

В данном примере чётко видно, какой путь исполнения у программы. Смотрим снизу вверх и по шагам понимаем, как же мы докатились до такого исключения.

Рассмотрим какие ещё встречаются комментарии к исключениям:

>>> 2 + '1'
Traceback (most recent call last):
  File "", line 1, in
    2 + '1'
TypeError: unsupported operand type(s) for +: 'int' and 'str'

В данном примере при попытке сложить целое число и строку мы получаем исключение TypeError. В описании сразу же становится ясно, что же мы не так написали.

>>> int('qwerty')
Traceback (most recent call last):
  File "", line 1, in
    int('qwerty')
ValueError: invalid literal for int() with base 10: 'qwerty'

Приведение строчки к целому числу приводит к исключению ValueError.

В трэйсе этих двух примеров можно прочесть, что в таком-то файле на такой-то строчке есть ошибки.

На этом список встроенных исключений не заканчивается, в следующем разделе рассмотрены основные исключения и причины их возникновения.

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

Исключение, которое вы не увидите при выполнении кода – это BaseException – базовое исключение, от которого берут начало остальные.

В иерархии исключений две основные группы:

  • Системные исключения и ошибки
  • Обыкновенные исключения

Если обработку первых лучше не делать (если и делать, то надо четко понимать для чего), то обработку вторых целиком и полностью Python возлагает на плечи программиста.

К системным можно смело отнести:

  • SystemExit – исключение, порождаемое функцией sys.exit при выходе из программы.
  • KeyboardInterrupt – возникает при прерывании программы пользователем (обычно сочетанием клавиш Ctrl+C).
  • GeneratorExit — возникает при вызове метода close объекта generator.

Остальные исключения – это «обыкновенные». Спектр уже готовых исключений велик.

Для Python2 иерархию исключений можно представить так:

Список исключений покрывает большой объем ситуаций и ошибок программиста. Если предупреждения (warning) только просят обратить внимание, то ошибки уже могут остановить исполнение программы.

В Python3 появились новые исключения и иерархия стала такова:

В целом заметно, что при создании Python3 добавлен блок новых исключений. Но даже этих почти 70 исключений не хватает при написании программ на языке Python.

Использование исключений

Мы рассмотрели что такое исключения, какие они бывают и как их анализировать. Но до сих пор явно не рассмотрели такую важную вещь, как их использование.

Начнем с обработки.

Обработка исключений

Давайте рассмотрим случай с делением на 0.

>>> a = 100
>>> b = 0
>>> c = a / b

Данный код приведет к исключению ZeroDivisionError. Чтобы этого не случилось, воспользуемся конструкцией

try..except, например, так:

>>> try:
...     a = 100
...     b = 0
...     c = a / b
... except ZeroDivisionError as e:
...     print(e)
...
division by zero

Если исполнить этот код, то на консоль будет выведена строка «integer division or modulo by zero«. Казалось бы, что толком ничего это нам не дало, ошибка все также есть. Однако в блок except можно поместить обработку.

Например, мы условились, что значение переменной c в случае ошибки деления равно -1. Тогда модифицируем код:

>>> try:
...     a = 100
...     b = 0
...     c = a / b
... except ZeroDivisionError as e:
.
.. c = -1 >>> c -1

Перед тем как идти дальше, рассмотрим ещё одну возможность.

Пускай у нас файл с данными в файловой системе, и необходимо его прочитать. В этом случае сразу же всплывают несколько исключительных ситуаций, такие как: нет файла, файл битый, файл пустой (по заданию мы знаем, что в нём данные) и другие.

Используя исключения, можно вот так решить эту задачу:

try:
    filepath = 'test_file.txt'
    with open(filepath, 'r') as fio:
        result = fio.readlines()
    if not result:
        raise Exception("File is empty")
except IOError as e:
    result = []
except Exception as e:
    result = []
    print(e)

В данном вымышленном коде новый ход – перехват нескольких видов исключений. Когда исключение брошено, оно сравнивается сверху вниз с каждым типом, пока не найдено совпадение. Если совпадения нет, то исключение пойдет наверх по цепочке исполнения кода.

Если обработка для разных типов исключений одинакова, то уменьшить количество кода становится не проблемой:

try:
    your_code
except (IOError, Exception) as e:
    print(e)

Вызов исключений

При работе с исключениями программист тратит большую часть времени на обработку, но при этом возникают ситуации, когда исключениями надо и бросать в других.

На сленге программистов «бросить исключение» означает написать код, который при исполнении будет инициировать исключительную ситуацию.

Например, функция, которая решает квадратное уравнение. Вы условились, что корни только вещественные, тогда в случае комплексных корней стоит бросить исключение.

Чтобы бросить исключение необходимо воспользоваться raise

Пример:

raise IOError("текст исключения")

где IOError это класс исключения.

Если при обработке исключения вы желаете пробросить его ещё выше, то следует написать такой код:

try:
    your_code
except Exception as e:
    raise

Собственные исключения

При написании собственных программ разумное желание добавить выразительности коду, а так же обратить внимание других программистов на особые исключительные ситуации. Для решения этой задачи стоит использовать собственные исключения.

В минимальном исполнении необходимо наследоваться от какого-нибудь класса в иерархии исключений. Например так:

class MyException(Exception):
    pass

Тогда можно бросить своё исключение:

raise MyException(Exception)

Легко заметить, мы создаем класс, а значит всё, что мы знаем о классах, справедливо и для исключений. Можно завести переменные и делать их обработку.

Как правило, исключения это очень маленькие классы. Они должны выполняться максимально быстро.

Дополнение: Полная форма try..except

Форма try...except не полная, полной же является try..except..else..finally.

Применение полной конструкции может заметно упростить код, а также сделать его более безопасным.

Представим, что в программе происходит чтение файла и необходимо убедиться, что объект файла был корректно закрыт и что не возникло никакого исключения. Этого можно достичь с применением блока finally.

Иными словами, finally выполняет блок инструкций в любом случае, было ли исключение, или нет. А инструкция else выполняется в том случае, если исключения не было.

В целом, использование полной формы таково:

try:
    исполяем какой-то код
except Exception as e:
    обработка исключения
else:
    код, который будет исполнен в случае, когда не возникает исключения
finally:
    код, который гарантированно будет исполнен последним (всегда исполняется)

Выводы

В уроке рассмотрены вопросы связанные с исключениями:

  • Что такое исключение
  • Какие типы исключений присутствуют в языке
  • Как обрабатывать исключения
  • Как вызвать исключения
  • Как создавать собственные исключения

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

except и обработка разных типов исключений

Последнее обновление: 30.01.2022

Встроенные типы исключений

В примере выше обрабатывались сразу все исключения, которые могут возникнуть в коде. Однако мы можем конкретизировать тип обрабатываемого исключения, указав его после слова except:


try:
    number = int(input("Введите число: "))
    print("Введенное число:", number)
except ValueError:
    print("Преобразование прошло неудачно")
print("Завершение программы")


В данном случае блок execpt обрабатывает только исключения типа ValueError, которые могут возникнут при неудачном преобразовании строки в число.

В Python есть следующие базовые типы исключений:

  • BaseException: базовый тип для всех встроенных исключений

  • Exception: базовый тип, который обычно применяется для создания своих типов исключений

  • ArithmeticError: базовый тип для исключений, связанных с арифметическими операциями (OverflowError, ZeroDivisionError, FloatingPointError).

  • BufferError: тип исключения, которое возникает при невозможности выполнить операцию с буффером

  • LookupError: базовый тип для исключений, которое возникают при обращении в коллекциях по некорректному ключу или индексу (например, IndexError, KeyError)

От этих классов наследуются все конкретные типы исключений. В Python обладает довольно большим списком встроенных исключений. Весь этот список можно посмотреть в документации. Перечислю только некоторые наиболее часто встречающиеся:

  • IndexError: исключение возникает, если индекс при обращении к элементу коллекции находится вне допустимого диапазона

  • KeyError: возникает, если в словаре отсутствует ключ, по которому происходит обращение к элементу словаря.

  • OverflowError: возникает, если результат арифметической операции не может быть представлен текущим числовым типом (обычно типом float).

  • RecursionError: возникает, если превышена допустимая глубина рекурсии.

  • TypeError: возникает, если операция или функция применяется к значению недопустимого типа.

  • ValueError: возникает, если операция или функция получают объект корректного типа с некорректным значением.

  • ZeroDivisionError: возникает при делении на ноль.

  • NotImplementedError: тип исключения для указания, что какие-то методы класса не реализованы

  • ModuleNotFoundError: возникает при при невозможности найти модуль при его импорте директивой import

  • OSError: тип исключений, которые генерируются при возникновении ошибок системы (например, невозможно найти файл, память диска заполнена и т.д.)

И если ситуация такова, что в программе могут быть сгенерированы различные типы исключений, то мы можем их обработать по отдельности, используя дополнительные выражения except. И при возникновении исключения Python будет искать нужный блок except, который обрабатывает данный тип исключения:


try:
    number1 = int(input("Введите первое число: "))
    number2 = int(input("Введите второе число: "))
    print("Результат деления:", number1/number2)
except ValueError:
    print("Преобразование прошло неудачно")
except ZeroDivisionError:
    print("Попытка деления числа на ноль")
except BaseException:
    print("Общее исключение")
print("Завершение программы")

Если возникнет исключение в результате преобразования строки в число, то оно будет обработано блоком except ValueError. Если же второе число будет равно нулю, то есть будет деление на ноль, тогда возникнет исключение ZeroDivisionError, и оно будет обработано блоком except ZeroDivisionError.

Тип BaseException представляет общее исключение, под которое попадают все исключительные ситуации. Поэтому в данном случае любое исключение, которое не представляет тип ValueError или ZeroDivisionError, будет обработано в блоке except BaseException:.

Однако, если в программе возникает исключение типа, для которого нет соответствующего блока except, то программа не сможет найти соответствующий блок except и сгенерирует исключение. Например, в следующем случае:


try:
    number1 = int(input("Введите первое число: "))
    number2 = int(input("Введите второе число: "))
    print("Результат деления:", number1/number2)
except ZeroDivisionError:
    print("Попытка деления числа на ноль")
print("Завершение программы")

Здесь предусмотрена обработка деления на ноль с помощью блока except ZeroDivisionError. Однако если пользователь вместо числа введет некорвертиуремую в число в строку, то возникнет исключение типа ValueError, для которого нет соответствующего блока except. И поэтому программа аварийно завершит свое выполнение.

Python позволяет в одном блоке except обрабатывать сразу несколько типов исключений. В этом случае все типы исключения передаются в скобках:


try:
    number1 = int(input("Введите первое число: "))
    number2 = int(input("Введите второе число: "))
    print("Результат деления:", number1/number2)
except (ZeroDivisionError, ValueError):    #  обработка двух типов исключений - ZeroDivisionError и ValueError
    print("Попытка деления числа на ноль или некорректный ввод")

print("Завершение программы")

Получение информации об исключении

С помощью оператора as мы можем передать всю информацию об исключении в переменную, которую затем можно использовать в блоке except:


try:
    number = int(input("Введите число: "))
    print("Введенное число:", number)
except ValueError as e:
    print("Сведения об исключении", e)
print("Завершение программы")

Пример некорректного ввода:


Введите число: fdsf
Сведения об исключении invalid literal for int() with base 10: 'fdsf'
Завершение программы

НазадСодержаниеВперед

errno — Стандартные системные символы errno — Документация Python 3.

11.2

Этот модуль предоставляет стандартные системные символы errno . Значение каждого символ — соответствующее целочисленное значение. Названия и описания есть заимствован из linux/include/errno.h , который должен быть все включено.

код ошибки

Словарь, обеспечивающий сопоставление значения errno с именем строки в базовая система. Например, errno.errorcode[errno.EPERM] сопоставляется с 'ЭПЕРМ' .

Чтобы преобразовать числовой код ошибки в сообщение об ошибке, используйте os.strerror() .

Из следующего списка символы, которые не используются на текущей платформе, не определяется модулем. Конкретный список определенных символов доступен как код_ошибки.keys() . Доступные символы могут включать:

номер ошибки.EPERM

Операция не разрешена. Эта ошибка сопоставляется с исключением Ошибка разрешения .

ошибка.ENOENT

Нет такого файла или каталога. Эта ошибка сопоставляется с исключением FileNotFoundError .

номер ошибки.ESRCH

Нет такого процесса. Эта ошибка сопоставляется с исключением ProcessLookupError .

номер ошибки.EINTR

Прерванный системный вызов. Эта ошибка сопоставляется с исключением Прерванная ошибка .

номер ошибки.EIO

Ошибка ввода/вывода

ошибка ENXIO

Нет такого устройства или адреса

номер ошибки.E2BIG

Список аргументов слишком длинный

ошибка.ENOEXEC

Ошибка формата Exec

номер ошибки.EBADF

Неверный номер файла

errno.ECHILD

Нет дочерних процессов. Эта ошибка сопоставляется с исключением Ошибка дочернего процесса .

ошибка.EAGAIN

Попробуйте еще раз. Эта ошибка сопоставляется с исключением BlockingIOError .

номер ошибки.ENOMEM

Недостаточно памяти

ошибка.EACCES

Отказано в доступе. Эта ошибка сопоставляется с исключением Ошибка разрешения .

ошибка.EFAULT

Неверный адрес

номер ошибки.ENOTBLK

Требуется блочное устройство

номер ошибки.EBUSY

Устройство или ресурс занят

ошибка.EEXIST

Файл существует. Эта ошибка сопоставляется с исключением FileExistsError .

номер ошибки.EXDEV

Связь между устройствами

ошибка. ENODEV

Нет такого устройства

errno.ENOTDIR

Не каталог. Эта ошибка сопоставляется с исключением NotADirectoryError .

номер ошибки.EISDIR

Каталог. Эта ошибка сопоставляется с исключением IsADirectoryError .

ошибка.EINVAL

Неверный аргумент

ошибка.ENFILE

Переполнение таблицы файлов

ошибка.EMFILE

Слишком много открытых файлов

ошибка.ENOTTY

Не пишущая машинка

ошибка.ETXTBSY

Текстовый файл занят

номер ошибки.EFBIG

Файл слишком большой

номер ошибки.ENOSPC

На устройстве не осталось места

ошибка.ESPIPE

Незаконный поиск

ошибка. EROFS

Файловая система только для чтения

номер ошибки.EMLINK

Слишком много ссылок

номер ошибки.EPIPE

Сломанная труба. Эта ошибка сопоставляется с исключением BrokenPipeError .

номер ошибки.EDOM

Математический аргумент вне области действия функции

ошибка.ERANGE

Непредставимый математический результат

номер ошибки.EDEADLK

Произойдет взаимоблокировка ресурса

errno.ENAMETOOLONG

Имя файла слишком длинное

номер ошибки.ENOLCK

Блокировки записей недоступны

ошибка.ENOSYS

Функция не реализована

ошибка.ENOTEMPTY

Каталог не пустой

ошибка.ELOOP

Обнаружено слишком много символических ссылок

errno. EWOULDBLOCK

Операция будет заблокирована. Эта ошибка сопоставляется с исключением Блокировка IOError .

номер ошибки.ENOMSG

Нет сообщения нужного типа

номер ошибки.EIDRM

Идентификатор удален

ошибка.ECHRNG

Номер канала вне допустимого диапазона

ошибка.EL2NSYNC

Уровень 2 не синхронизирован

номер ошибки.EL3HLT

Уровень 3 остановлен

номер ошибки.EL3RST

Сброс уровня 3

номер ошибки.ELNRNG

Номер ссылки вне допустимого диапазона

ошибка.EUNATCH

Драйвер протокола не подключен

ошибка.ENOCSI

Структура CSI отсутствует

номер ошибки.EL2HLT

Уровень 2 остановлен

номер ошибки. EBADE

Неверный обмен

номер ошибки.EBADR

Недопустимый дескриптор запроса

ошибка.EXFULL

Полный обмен

errno.ENOANO

Без анода

номер ошибки EBADRQC

Неверный код запроса

номер ошибки.EBADST

Неверный слот

errno.EDEADLOCK

Ошибка блокировки файла

номер ошибки.EBFONT

Неверный формат файла шрифта

номер ошибки.ENOSTR

Устройство не является потоком

errno.ENODATA

Нет данных

ошибка.ETIME

Таймер истек

номер ошибки.ENOSR

Вне потоков ресурсов

номер ошибки.ENONET

Машина не в сети

номер ошибки. ENOPKG

Пакет не установлен

errno.REMOTE

Объект удален

ошибка.ENOLINK

Связь разорвана

номер ошибки.EADV

Ошибка объявления

номер ошибки.ESRMNT

Ошибка запуска

ошибка.COMM

Ошибка связи при отправке

ошибка.EPROTO

Ошибка протокола

errno.EMULTIHOP

Многоскачковая попытка

номер ошибки.EDOTDOT

Специфическая ошибка RFS

номер ошибки.EBADMSG

Не сообщение данных

errno.EOVERFLOW

Слишком большое значение для определенного типа данных

номер ошибки.ENOTUNIQ

Имя не уникально в сети

номер ошибки. EBADFD

Файловый дескриптор в плохом состоянии

errno.EREMCHG

Удаленный адрес изменен

номер ошибки.ELIBACC

Не удается получить доступ к необходимой общей библиотеке

номер ошибки.ELIBBAD

Доступ к поврежденной общей библиотеке

номер ошибки.ELIBSCN

Раздел .lib в a.out поврежден

номер ошибки.ELIBMAX

Попытка связать слишком много общих библиотек

ошибка.ELIBEXEC

Невозможно запустить общую библиотеку напрямую

номер ошибки.EILSEQ

Недопустимая последовательность байтов

errno.ERRESTART

Прерванный системный вызов следует перезапустить

ошибка.ESTRPPIPE

Ошибка канала потоков

ошибка. EUSERS

Слишком много пользователей

ошибка.ENOTSOCK

Работа сокета без сокета

errno.EDESTADDRREQ

Требуется адрес назначения

ошибка.EMSGSIZE

Сообщение слишком длинное

errno.EPROTOTYPE

Неверный тип протокола для сокета

errno.ENOPROTOOPT

Протокол недоступен

ошибка.EPROTONOSUPPORT

Протокол не поддерживается

ошибка ESOCKTNOSUPPORT

Тип сокета не поддерживается

ошибка.EOPNOTSUPP

Операция не поддерживается на конечной точке транспорта

номер ошибки.EPFNOSUPPORT

Семейство протоколов не поддерживается

ошибка.EAFNOSUPPORT

Семейство адресов не поддерживается протоколом

ошибка. EADDRINUSE

Адрес уже используется

errno.EADDRNOTAVAIL

Невозможно назначить запрошенный адрес

ошибка.ENETDOWN

Сеть не работает

errno.ENETUNREACH

Сеть недоступна

ошибка ENETRESET

Сетевое соединение разорвано из-за сброса

errno.ECONNABORTED

Программное обеспечение вызвало разрыв соединения. Эта ошибка сопоставляется с исключение ConnectionAbortedError .

errno.ECONNRESET

Соединение сброшено узлом. Эта ошибка сопоставляется с исключением ConnectionResetError .

ошибка.ENOBUFS

Нет свободного места в буфере

номер ошибки EISCONN

Конечная точка транспорта уже подключена

номер ошибки. ENOTCONN

Конечная точка транспорта не подключена

errno.ESHUTDOWN

Не удается отправить после завершения работы конечной точки транспорта. Эта ошибка отображается к исключению BrokenPipeError .

errno.ETOOMANYREFS

Слишком много ссылок: невозможно соединить

ошибка.ETIMEDOUT

Время ожидания соединения истекло. Эта ошибка сопоставляется с исключением Ошибка тайм-аута .

errno.ECONREFUSED

В соединении отказано. Эта ошибка сопоставляется с исключением ConnectionRefusedError .

ошибка.EHOSTDOWN

Хост недоступен

ошибка.EHOSTUNREACH

Нет маршрута к хосту

errno.EALREADY

Операция уже выполняется. Эта ошибка сопоставляется с исключение BlockingIOError .

ошибка.EINPROGRESS

Выполняется операция. Эта ошибка сопоставляется с исключением Блокировка IOError .

errno.ESTALE

Устаревший дескриптор файла NFS

ошибка.EUCLEAN

Требуется очистка конструкции

номер ошибки.ENOTNAM

Не является файлом именованного типа XENIX

errno.ENAVAIL

Нет доступных семафоров XENIX

номер ошибки.EISNAM

Является файлом именованного типа

errno.EREMOTEIO

Ошибка удаленного ввода/вывода

ошибка.EDQUOT

Превышена квота

ошибка.EQFULL

Очередь вывода интерфейса заполнена

Новое в версии 3.11.

errno.ENOTCAPABLE

Возможностей недостаточно. Эта ошибка сопоставляется с исключением Ошибка разрешения .

Наличие: WASI, FreeBSD

Новое в версии 3.11.1.

предупреждений — Управление предупреждениями — Документация Python 3.11.2

Исходный код: Lib/warnings.py


Предупреждающие сообщения обычно выдаются в ситуациях, когда полезно пользователь некоторого условия в программе, где это условие (обычно) не ордер на возбуждение исключения и завершение программы. Например, один может захотеть выдать предупреждение, когда программа использует устаревший модуль.

Программисты Python выдают предупреждения, вызывая функцию warn() , определенную в этом модуле. (программисты на C используют PyErr_WarnEx() ; видеть Подробности об обработке исключений).

Предупреждающие сообщения обычно записываются в sys.stderr , но их расположение можно гибко менять, от игнорирования всех предупреждений до превращения их в исключения. Расположение предупреждений может различаться в зависимости от категории предупреждения, текста предупреждающего сообщения и исходного расположения, в котором оно находится. выпущен. Повторы конкретного предупреждения для одного и того же источника запрещены. обычно подавляется.

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

Решение о том, выдавать ли предупреждающее сообщение, контролируется фильтр предупреждений, представляющий собой последовательность соответствующих правил и действий. Правила могут быть добавлен в фильтр, вызвав filterwarnings() и сброшен по умолчанию состояние, вызвав resetwarnings() .

Печать предупреждающих сообщений выполняется вызовом showwarning() , который может быть переопределен; реализация этой функции по умолчанию форматирует сообщение, вызвав formatwarning() , который также доступен для использования пользовательские реализации.

См. также

logging.captureWarnings() позволяет обрабатывать все предупреждения с помощью стандартная инфраструктура регистрации.

Категории предупреждений

Существует ряд встроенных исключений, представляющих категории предупреждений. Эта категоризация полезна для возможности фильтрации групп предупреждений.

Хотя технически это встроенные исключения, они задокументированы здесь, потому что концептуально они относятся к механизму предупреждений.

Код пользователя может определять дополнительные категории предупреждений путем подкласса одного из стандартные категории предупреждений. Категория предупреждений всегда должна быть подклассом класс Предупреждение .

В настоящее время определены следующие классы категорий предупреждений:

Класс

Описание

Предупреждение

Это базовый класс всех предупреждений. классы категорий. Это подкласс Исключение .

Предупреждение пользователя

Категория по умолчанию для warn() .

Предупреждение об устаревании

Базовая категория для предупреждений об устаревших функции, когда эти предупреждения предназначены для другие разработчики Python (по умолчанию игнорируются, если это не вызвано кодом в __main__ ).

Предупреждение о синтаксисе

Базовая категория для предупреждений о сомнительных синтаксические особенности.

RuntimeWarning

Базовая категория для предупреждений о сомнительных особенности выполнения.

FutureWarning

Базовая категория для предупреждений об устаревших функции, когда эти предупреждения предназначены для конечные пользователи приложений, написанных на Питон.

PendingDeprecationWarning

Базовая категория для предупреждений о функциях который будет устарел в будущем (игнорируется по умолчанию).

Предупреждение об импорте

Базовая категория для предупреждений, срабатывающих во время процесс импорта модуля (игнорируется по умолчанию).

UnicodeWarning

Базовая категория для предупреждений, связанных с Юникод.

BytesWarning

Базовая категория для предупреждений, связанных с байта и bytearray .

Предупреждение о ресурсах

Базовая категория для предупреждений, связанных с использование ресурсов (по умолчанию игнорируется).

Изменено в версии 3.7: Ранее Предупреждение об устаревании и FutureWarning были различаются в зависимости от того, удалялась ли функция полностью или изменение своего поведения. Теперь их различают по их предполагаемая аудитория и то, как они обрабатываются предупреждениями по умолчанию фильтры.

Фильтр предупреждений

Фильтр предупреждений определяет, будут ли предупреждения игнорироваться, отображаться или в ошибки (возбуждение исключения).

Концептуально фильтр предупреждений поддерживает упорядоченный список фильтров. Характеристики; любое конкретное предупреждение сопоставляется с каждым фильтром спецификацию в списке по очереди, пока не будет найдено совпадение; фильтр определяет диспозиция матча. Каждая запись представляет собой кортеж вида ( действие , сообщение , категория , модуль , линейно ), где:

  • действие является одной из следующих строк:

    Значение

    Распоряжение

    "по умолчанию"

    вывести первое совпадение предупреждения для каждой локации (модуль + номер строки), где выдается предупреждение

    "ошибка"

    превратить соответствующие предупреждения в исключения

    "игнорировать"

    никогда не печатать соответствующие предупреждения

    "всегда"

    всегда печатать соответствующие предупреждения

    "модуль"

    вывести первое совпадение предупреждения для каждого модуля, где предупреждение выдается (независимо от номера строки)

    "один раз"

    печатать только первое совпадение предупреждения, независимо от местонахождения

  • сообщение — это строка, содержащая регулярное выражение, начало которого предупреждающее сообщение должно совпадать без учета регистра. В -W и PYTHONWARNINGS , сообщение — буквальная строка, которая является началом предупреждающее сообщение должно содержать (без учета регистра), игнорируя любые пробелы в начало или конец сообщение .

  • категория — это класс (подкласс Предупреждение ), для которого предупреждение категория должна быть подклассом, чтобы соответствовать.

  • модуль представляет собой строку, содержащую регулярное выражение, которое является началом полное имя модуля должно совпадать с учетом регистра. В -W и PYTHONWARNINGS , модуль — это литеральная строка, которую полное имя модуля должно быть равно (с учетом регистра), игнорируя любые пробел в начале или в конце модуль .

  • lineno — целое число, которое должно соответствовать номеру строки, в которой появилось предупреждение. match или 0 для соответствия всем номерам строк.

Поскольку класс Warning является производным от встроенного Exception class, чтобы превратить предупреждение в ошибку, мы просто поднимаем категорию (сообщение) .

Если сообщается о предупреждении, которое не соответствует ни одному зарегистрированному фильтру, то применяется действие «по умолчанию» (отсюда и его название).

Описание фильтров предупреждений

Фильтр предупреждений инициализируется параметрами -W , переданными в Python командная строка интерпретатора и переменная среды PYTHONWARNINGS . Интерпретатор сохраняет аргументы для всех предоставленных записей без интерпретация в sys.warnoptions ; модуль warnings анализирует эти при первом импорте (недопустимые параметры игнорируются, после печати сообщение на sys.stderr ).

Фильтры отдельных предупреждений задаются в виде последовательности полей, разделенных двоеточия:

 действие: сообщение: категория: модуль: строка
 

Значение каждого из этих полей соответствует описанию в разделе Фильтр предупреждений. При перечислении нескольких фильтров в одной строке (например, PYTHONWARNINGS ), отдельные фильтры разделяются запятыми и фильтры, перечисленные ниже, имеют приоритет над теми, которые перечислены перед ними (как они применяются слева направо, а самые последние примененные фильтры занимают приоритет перед предыдущими).

Обычно используемые фильтры предупреждений применяются либо ко всем предупреждениям, либо к предупреждениям в конкретной категории или предупреждений, выдаваемых определенными модулями или пакетами. Некоторые примеры:

 default # Показать все предупреждения (даже игнорируемые по умолчанию)
ignore # Игнорировать все предупреждения
error # Преобразовать все предупреждения в ошибки
error::ResourceWarning # Рассматривать сообщения ResourceWarning как ошибки
default::DeprecationWarning # Показать сообщения DeprecationWarning
ignore,default:::mymodule # Сообщать только о предупреждениях, вызванных "mymodule"
error:::mymodule # Преобразование предупреждений в ошибки в "mymodule"
 

Фильтр предупреждений по умолчанию

По умолчанию Python устанавливает несколько фильтров предупреждений, которые можно переопределить с помощью параметр командной строки -W , среда PYTHONWARNINGS переменная и вызывает filterwarnings() .

В сборках обычных выпусков фильтр предупреждений по умолчанию имеет следующие записи. (в порядке старшинства):

 по умолчанию::DeprecationWarning:__main__
игнорировать::DeprecationWarning
ignore::PendingDeprecationWarning
игнорировать:: ИмпортВарнинг
игнорировать:: ResourceWarning
 

В отладочной сборке список фильтров предупреждений по умолчанию пуст.

Изменено в версии 3.2: DeprecationWarning теперь игнорируется по умолчанию в дополнение к PendingDeprecationWarning .

Изменено в версии 3.7: DeprecationWarning снова отображается по умолчанию при срабатывании напрямую по коду __main__ .

Изменено в версии 3.7: BytesWarning больше не отображается в списке фильтров по умолчанию и вместо этого настроен через sys.warnoptions , когда указано -b дважды.

Переопределение фильтра по умолчанию

Разработчики приложений, написанных на Python, могут захотеть скрыть все уровни Python предупреждения от своих пользователей по умолчанию и отображать их только при запуске тестов или иным образом работает над приложением. Атрибут sys.warnoptions используется для передачи настроек фильтра интерпретатору, может использоваться в качестве маркера для указать, следует ли отключать предупреждения:

 система импорта
если не sys.warnoptions:
    предупреждения об импорте
    предупреждения.simplefilter("игнорировать")
 

Разработчикам тестовых исполнителей для кода Python рекомендуется вместо этого убедиться, что все предупреждения отображаются по умолчанию для тестируемого кода с использованием кода как:

 система импорта
если не sys.warnoptions:
    импорт ОС, предупреждения
    warnings.simplefilter("default") # Изменить фильтр в этом процессе
    os.environ["PYTHONWARNINGS"] = "default" # Также влияет на подпроцессы
 

Наконец, разработчики интерактивных оболочек, выполняющих пользовательский код в пространстве имен. кроме __main__ рекомендуется убедиться, что DeprecationWarning сообщения становятся видимыми по умолчанию с помощью кода, подобного следующему (где user_ns — это модуль, используемый для выполнения кода, введенного в интерактивном режиме):

 предупреждения об импорте
warnings. filterwarnings("по умолчанию", category=Предупреждение об устаревании,
                                   модуль = user_ns.get ("__ имя__"))
 

Временное подавление предупреждений

Если вы используете код, который, как вы знаете, вызовет предупреждение, например устаревшее функции, но не хотят видеть предупреждение (даже если предупреждения были явно настраивается через командную строку), то есть возможность подавить предупреждение с использованием менеджера контекста catch_warnings :

 предупреждения об импорте
защита fxn():
    warnings.warn("устарело", DeprecationWarning)
с предупреждениями.catch_warnings():
    предупреждения.simplefilter("игнорировать")
    fxn()
 

В менеджере контекста все предупреждения будут просто игнорироваться. Этот позволяет вам использовать заведомо устаревший код без необходимости видеть предупреждение во время не подавлять предупреждение для другого кода, который может не знать о его использовании устаревшего кода. Примечание: это может быть гарантировано только в однопоточном приложение. Если два или более потока используют контекст catch_warnings менеджер в то же время, поведение не определено.

Предупреждения тестирования

Чтобы протестировать предупреждения, вызванные кодом, используйте catch_warnings контекст менеджер. С его помощью вы можете временно изменить фильтр предупреждений, чтобы облегчить ваше тестирование. Например, сделайте следующее, чтобы зафиксировать все поднятые предупреждения в чек:

 предупреждения об импорте
защита fxn():
    warnings.warn("устарело", DeprecationWarning)
с warnings.catch_warnings(record=True) как w:
    # Сделать так, чтобы все предупреждения всегда срабатывали.
    предупреждения.simplefilter("всегда")
    # Вывести предупреждение.
    fxn()
    # Проверить некоторые вещи
    утверждать len(w) == 1
    утверждать issubclass(w[-1].category, DeprecationWarning)
    утверждать "устаревшее" в строке (w[-1]. message)
 

Можно также сделать все предупреждения исключениями, используя ошибку вместо всегда . Одна вещь, о которой следует помнить, это то, что если предупреждение уже было поднял из-за раз / правило по умолчанию , то без разницы какие фильтры стоят установите, что предупреждение больше не будет отображаться, если только реестр предупреждений, связанный с предупреждение было удалено.

После выхода из диспетчера контекста фильтр предупреждений возвращается в исходное состояние. когда был введен контекст. Это предотвращает изменение предупреждений тестами. фильтруют неожиданным образом между тестами и приводят к неопределенным тестам Результаты. функция showwarning() в модуле также восстанавливается до его первоначальное значение. Примечание: это может быть гарантировано только в однопоточном приложение. Если два или более потока используют контекст catch_warnings менеджер в то же время, поведение не определено.

При тестировании нескольких операций, вызывающих одинаковые предупреждения, важно протестировать их таким образом, чтобы подтвердить, что каждая операция поднимает новое предупреждение (например, настроить предупреждения как исключения и проверить операции вызывают исключения, убедитесь, что длина списка предупреждений продолжает увеличиваться после каждой операции, либо удалить предыдущую записи из списка предупреждений перед каждой новой операцией).

Обновление кода для новых версий зависимостей

Категории предупреждений, которые в первую очередь представляют интерес для разработчиков Python (скорее чем конечные пользователи приложений, написанных на Python) по умолчанию игнорируются.

Примечательно, что этот список «игнорируется по умолчанию» включает DeprecationWarning (для каждого модуля, кроме __main__ ), что означает, что разработчики должны убедиться для тестирования своего кода с обычно игнорируемыми предупреждениями, сделанными видимыми, чтобы получать своевременные уведомления о будущих критических изменениях API (будь то в стандартная библиотека или сторонние пакеты).

В идеальном случае код будет иметь подходящий набор тестов, а программа запуска тестов позаботится о неявном включении всех предупреждений при запуске тестов (это делает средство запуска тестов, предоставляемое модулем unittest ).

В менее идеальных случаях приложения могут быть проверены на использование устаревших интерфейсы, передав -Wd интерпретатору Python (это сокращение для -W по умолчанию ) или установка PYTHONWARNINGS= по умолчанию в окружающая среда. Это включает обработку по умолчанию для всех предупреждений, включая которые игнорируются по умолчанию. Чтобы изменить действие, предпринимаемое для обнаруженных предупреждения вы можете изменить, какой аргумент передается на -W (например, -W ошибка ). См. флаг -W для получения более подробной информации о том, что возможный.

Доступные функции

warnings.warn( сообщение , категория=Нет , уровень стека=1 , источник=Нет )

Выдать предупреждение или, возможно, проигнорировать его или вызвать исключение. Категория аргумент, если он задан, должен быть классом категории предупреждений; это по умолчанию UserWarning . В качестве альтернативы 9Сообщение 1291 может быть экземпляром Warning , в этом случае категория будет проигнорирована и будет использоваться message.__class__ . В этом случае текст сообщения будет str(message) . Эта функция вызывает исключение, если конкретное выданное предупреждение изменено на ошибку фильтр предупреждений. Аргумент stacklevel может использоваться оболочкой функции, написанные на Python, например:

 дерекламация (сообщение):
    warnings.warn (сообщение, предупреждение об устаревании, уровень стека = 2)
 

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

источник , если указан, это уничтоженный объект, испустивший Предупреждение о ресурсе .

Изменено в версии 3.6: Добавлен параметр source .

warnings.warn_explicit( сообщение , категория , имя файла , lineno , модуль=нет , реестр=нет , module_globals=нет , источник=нет )

Это низкоуровневый интерфейс для функций warn() , переходящий в явно сообщение, категорию, имя файла и номер строки, и, возможно, имя модуля и реестр (который должен быть __warningregistry__ словарь модуля). Имя модуля по умолчанию равно имени файла с .py раздели; если реестр не передается, предупреждение никогда не подавляется. сообщение должно быть строкой и категорией подклассом Предупреждение или Сообщение может быть экземпляром Warning , и в этом случае категория будет игнорируется.

module_globals , если указано, должно быть глобальным пространством имен, используемым кодом за что вынесено предупреждение. (Этот аргумент используется для поддержки отображения источник для модулей, найденных в zip-файлах или другом импорте, не относящемся к файловой системе источники).

источник , если указан, это уничтоженный объект, испустивший Предупреждение о ресурсе .

Изменено в версии 3.6: добавлен параметр источника .

warnings.showwarning( сообщение , категория , имя файла , lineno , file=None , line=None )

Записать предупреждение в файл. Реализация по умолчанию вызывает formatwarning(сообщение, категория, имя файла, номер строки, строка) и пишет результирующая строка файл , который по умолчанию равен sys.stderr . Вы можете заменить эту функцию с любым вызываемым, назначив warnings.showwarning . строка — это строка исходного кода, которая должна быть включена в предупреждение сообщение; если строка не указана, showwarning() будет попробуйте прочитать строку, указанную имя файла и lineno .

предупреждения.formatwarning( сообщение , категория , имя файла , lineno , строка=нет )

Отформатировать предупреждение стандартным способом. Это возвращает строку, которая может содержать встроенные символы новой строки и заканчиваются новой строкой. строка — это строка исходного кода для быть включенным в предупреждающее сообщение; если строка не указана, formatwarning() попытается прочитать строку, указанную именем файла и линейно .

warnings.filterwarnings( action , message=» , category=Warning , module=» , lineno=0 , append=False )

Вставить запись в список спецификаций фильтра предупреждений. Запись вставляется впереди по умолчанию; если добавить верно, оно вставляется в конце. Это проверяет типы аргументы, компилирует сообщения и модуль регулярные выражения, и вставляет их как кортеж в список фильтров предупреждений. Записи ближе к в начале списка переопределяют записи, расположенные дальше в списке, если оба соответствуют конкретное предупреждение. Пропущенные аргументы по умолчанию соответствуют значению, которое соответствует все.

warnings.simplefilter( action , category=Warning , lineno=0 , append=False )

Вставить простую запись в список спецификаций фильтра предупреждений. Смысл параметров функции такой же, как для filterwarnings() , но регулярные выражения не нужны в качестве фильтра вставка всегда соответствует любому сообщению в любом модуле, если категория и номер строки совпадает.

предупреждения.resetwarnings()

Сбросить фильтр предупреждений. Это отменяет эффект всех предыдущих вызовов filterwarnings() , включая параметры командной строки -W и вызывает simplefilter() .

Доступные менеджеры контекста

класс warnings. catch_warnings( * , запись=ложь , модуль=нет , действие=нет , категория = предупреждение , lineno = 0 , добавление = ложь )

Менеджер контекста, который копирует и при выходе восстанавливает фильтр предупреждений и функция showwarning() . Если аргумент записи равен False (по умолчанию), менеджер контекста возвращает None при входе. Если запись равна True , список возвращается, который постепенно заполняется объектами, как их видит пользовательский показать предупреждение() (которая также подавляет вывод на sys.stdout ). Каждый объект в списке имеет атрибуты с теми же именами, что и аргументы для показать предупреждение() .

Аргумент модуля принимает модуль, который будет использоваться вместо модуль возвращается при импорте предупреждений , фильтр которых будет защищен.