Содержание

Обработка исключений python — try/except и raise

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

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

2. Обработка исключений в Python

Рассмотрим разные типы исключений в Python, которые появляются при срабатывании исключения в коде Python.

3. Блоки try/except

Если код может привести к исключению, его лучше заключить в блок try. Рассмотрим на примере.

try:
    for i in range(3):
        print(3/i)
except:
    print("Деление на 0")
    print("Исключение было обработано")

Программа вывела сообщение, потому что было обработано исключение.

Следом идет блок except. Если не определить тип исключения, то он будет перехватывать любые. Другими словами, это общий обработчик исключений.

Если код в блоке try приводит к исключению, интерпретатор ищет блок except, который указан следом. Оставшаяся часть кода в try исполнена не будет.

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

a. Несколько except в Python

У одного блока try может быть несколько блоков except. Рассмотрим примеры с несколькими вариантами обработки.

a, b = 1, 0
try:
    print(a/b)
    print("Это не будет напечатано")
    print('10'+10)
except TypeError:
    print("Вы сложили значения несовместимых типов")
except ZeroDivisionError:
    print("Деление на 0")

Когда интерпретатор обнаруживает исключение, он проверяет блоки except соответствующего блока try. В них может быть объявлено, какие типы исключений они обрабатывают. Если интерпретатор находит соответствующее исключение, он исполняет этот блок except.

В первом примере первая инструкция приводит к ZeroDivisionError. Эта ошибка обрабатывается в блоке except, но инструкции в try после первой не исполняются.

Так происходит из-за того, что после первого исключения дальнейшие инструкции просто пропускаются. И если подходящий или общий блоки except не удается найти, исключение не обрабатывается. В таком случае оставшаяся часть программы не будет запущена. Но если обработать исключение, то код после блоков except и finally исполнится. Попробуем.

a, b = 1, 0
try:
   print(a/b)
except:
   print("Вы не можете разделить на 0")
print("Будет ли это напечатано?")

Рассмотрим вывод:

Вы не можете разделить на 0
Будет ли это напечатано?

b. Несколько исключений в одном except

Можно использовать один блок except

для обработки нескольких исключений. Для этого используются скобки. Без них интерпретатор вернет синтаксическую ошибку.

try:
    print('10'+10)
    print(1/0)
except (TypeError,ZeroDivisionError):
    print("Неверный ввод")
Неверный ввод

c. Общий except после всех блоков except

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

try:
    print('1'+1)
    print(sum)
    print(1/0)
except NameError:
    print("sum не существует")
except ZeroDivisionError:
    print("Вы не можете разделить на 0")
except:
    print("Что-то пошло не так...")
Что-то пошло не так...

Здесь первая инструкция блока пытается осуществить операцию конкатенации строки python с числом. Это приводит к ошибке TypeError. Как только интерпретатор сталкивается с этой проблемой, он проверяет соответствующий блок except, который ее обработает.

Отдельную инструкцию нельзя разместить между блоками try и except.

try:
    print("1")
print("2")
except:
    print("3")

Это приведет к синтаксической ошибке.

Но может быть только один общий или блок по умолчанию типа except. Следующий код вызовет ошибку

«default 'except:' must be last»:

try:
    print(1/0)
except:
    raise
except:
    print("Исключение поймано")
finally:
    print("Хорошо")
print("Пока")

4.

Блок finally в Python

После последнего блока except можно добавить блок finally. Он исполняет инструкции при любых условиях.

try:
    print(1/0)
except ValueError:
    print("Это ошибка значения")
finally:
    print("Это будет напечатано в любом случае.")
Это будет напечатано в любом случае.
Traceback (most recent call last):  
  File “”, line 2, in   
    print(1/0)
ZeroDivisionError: division by zero

Стоит обратить внимание, что сообщение с ошибкой выводится после исполнения блока

finally. Почему же тогда просто не использовать print? Но как видно по последнему примеру, блок finally запускается даже в том случае, если перехватить исключение не удается.

А что будет, если исключение перехватывается в except?

try:
    print(1/0)
except ZeroDivisionError:
    print(2/0)
finally:
    print("Ничего не происходит")
Ничего не происходит
Traceback (most recent call last):
  File "", line 2, in 
    print(1/0)
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "", line 4, in 
    print(2/0)
ZeroDivisionError: division by zero

Как видите, код в блоке

finally исполняется в любом случае.

5. Ключевое слово raise в Python

Иногда нужно будет разбираться с проблемами с помощью вызова исключения. Обычная инструкция print тут не сработает.

raise ZeroDivisionError
Traceback (most recent call last):
  File "", line 1, in 
    raise ZeroDivisionError
ZeroDivisionError

Разберемся на примере операции деления:

a,b=int(input()),int(input())  # вводим 1 затем 0
if b==0:
    raise ZeroDivisionError
Traceback (most recent call last):
  File "", line 3, in 
    raise ZeroDivisionError
ZeroDivisionError

Здесь ввод пользователя в переменные

a и b конвертируется в целые числа. Затем проверяется, равна ли b нулю. Если да, то вызывается ZeroDivisionError.

Что будет, если то же самое добавить в блоки try-except? Добавим следующее в код. Если запустить его, ввести 1 и 0, будет следующий вывод:

a,b=int(input()),int(input())
try:
    if b==0:
        raise ZeroDivisionError
except:
   print("Деление на 0")
print("Будет ли это напечатано?")
1
0
Деление на 0
Будет ли это напечатано?

Рассмотрим еще несколько примеров, прежде чем двигаться дальше:

raise KeyError
Traceback (most recent call last):
  File “”, line 1, in 
    raise KeyError
KeyError

a.

Raise без определенного исключения в Python

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

try:
    print('1'+1)
except:
    raise
Traceback (most recent call last):
  File “”, line 2, in 
    print(‘1’+1)
TypeError: must be str, not int

b. Raise с аргументом в Python

Также можно указать аргумент к определенному исключению в raise. Делается это с помощью дополнительных деталей исключения.

raise ValueError("Несоответствующее значение")
Traceback (most recent call last):
  File "", line 1, in 
    raise ValueError("Несоответствующее значение")
ValueError: Несоответствующее значение

6. assert в Python

Утверждение (assert) — это санитарная проверка для вашего циничного, параноидального «Я». Оно принимает инструкцию в качестве аргумента и вызывает исключение Python, если возвращается значение False. В противном случае выполняет операцию No-operation (NOP).

assert(True)
#  код работает дальше

Если бы инструкция была False?


assert(1==0)
Traceback (most recent call last):
  File “”, line 1, in 
    assert(1==0)
AssertionError

Возьмем другой пример:

try:
    print(1)
    assert 2+2==4
    print(2)
    assert 1+2==4
    print(3)
except:
    print("assert False.")
    raise
finally:
    print("Хорошо")
print("Пока")

Вывод следующий:

1
2
assert False.
Хорошо
Traceback (most recent call last):
  File “”, line 5, in 
    assert 1+2==4
AssertionError

Утверждения можно использовать для проверки валидности ввода и вывода в функции.

a. Второй аргумент для assert

Можно предоставить второй аргумент, чтобы дать дополнительную информацию о проблеме.

assert False,"Это проблема"
Traceback (most recent call last):
  File “”, line 1, in 
    assert False,”Это проблема”
AssertionError: Это проблема

7.

Объявление собственных исключений Python

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

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

class MyError(Exception):
    print("Это проблема")
raise MyError("ошибка MyError")
Traceback (most recent call last):
  File “”, line 1, in 
    raise MyError(“ошибка MyError”)
MyError: ошибка MyError

Вот и все, что касается обработки исключений в Python.

8. Вывод: обработка исключений Python

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

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

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

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

При наличии таких ошибок программа не может быть скомпилирована. При работе в какой-либо среде разработки, например, в PyCharm, IDE сама может отслеживать синтаксические ошибки и каким-либо образом их выделять.

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


string = "5"
number = int(string)
print(number)

Данный скрипт успешно скомпилируется и выполнится, так как строка «5» вполне может быть конвертирована в число. Однако возьмем другой пример:


string = "hello"
number = int(string)
print(number)

При выполнении этого скрипта будет выброшено исключение ValueError, так как строку «hello» нельзя преобразовать в число:

ValueError: invalid literal for int() with base 10: 'hello'

С одной стороны, здесь очевидно, что строка не представляет число, но мы можем иметь дело с вводом пользователя, который также может ввести не совсем то, что мы ожидаем:


string = input("Введите число: ")
number = int(string)
print(number)

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

try..except

Конструкция try..except имеет следующее формальное определение:


try:
	инструкции
except [Тип_исключения]:
	инструкции

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

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

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


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

Вводим строку:


Введите число: hello
Преобразование прошло неудачно
Завершение программы

Как видно из консольного вывода, при вводе строки вывод числа на консоль не происходит, а выполнение программы переходит к блоку except.

Вводим правильное число:


Введите число: 22
Введенное число: 22
Завершение программы

Теперь все выполняется нормально, исключение не возникает, и соответственно блок except не выполняется.

Блок finally

При обработке исключений также можно использовать необязательный блок finally. Отличительной особенностью этого блока является то, что он выполняется вне зависимости, было ли сгенерировано исключение:


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

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

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

Примеры и рекомендации • Python Land Tutorial

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

Содержание

  • 1 Что такое исключение?
  • 2 Python try, кроме
  • 3 Перехват исключений с помощью try, кроме
  • 4 Блоки finally и else
  • 5 Распространенные исключения Python
  • 6 Рекомендации по работе с исключениями
  • 7 Создание пользовательских исключений
  • 9001 1 8 Вызов (или выбрасывание) исключений
  • 9 Как напечатать исключение Python
  • 10 Продолжайте учиться

Что такое исключение?

Исключение — это состояние, возникающее во время выполнения программы. Это сигнал о том, что произошло что-то неожиданное. Python представляет исключения объектом определенного типа.

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

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

 Исключение базы
 +-- Выход из системы
 +-- Прерывание Клавиатуры
 +-- Исключение
      +-- Ошибка арифметики
      | +-- Ошибка с плавающей запятой
      | +-- Ошибка переполнения
      | +-- ZeroDivisionError
      ..... 

Если ваши знания об объектах, классах и наследовании немного заржавели, вы можете сначала прочитать мою статью об объектах и ​​классах и мою статью о наследовании.

Попробуйте Python, кроме

Когда происходит что-то неожиданное, мы можем вызвать исключение в момент возникновения ошибки. Когда возникает исключение, Python останавливает текущий поток выполнения и начинает искать обработчик исключений, который может его обработать. Так что же такое обработчик исключений? Здесь в игру вступают операторы try и exclude.

попытаться.. кроме.. иначе.. наконец

Как показано на рисунке, мы можем создать блок кода, начав с оператора try. Это означает: попробуйте запустить этот код, но может возникнуть исключение .

После нашего блока try должны следовать один или несколько блоков exclude. Вот где происходит волшебство. Эти блоки исключения могут перехватывать исключение, как мы обычно это называем. На самом деле, многие другие языки программирования используют выражение catch вместо 9.0003 кроме . Каждый блок , кроме , может обрабатывать определенный тип исключения.

Помните: классы иерархичны. По этой причине исключения тоже. Следовательно, блоки исключений должны переходить от наиболее конкретных, таких как ZeroDivisionError , к менее конкретным, таким как ArithmeticError .

Чтобы продемонстрировать это, представьте, что произойдет, если мы начнем с блока exclude, который перехватывает Exception . Этот первый блок будет перехватывать в основном все, потому что большинство исключений наследуются от него, делая другие блоки, кроме блоков, бесполезными.

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

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

Стек вызовов

Стек вызовов — это упорядоченный список функций, которые выполняются в данный момент. Например, вы можете вызвать функцию A, которая вызывает функцию B, которая вызывает функцию C. Теперь у нас есть стек вызовов, состоящий из A, B и C. Когда C вызывает исключение, Python будет искать обработчик исключения в этом вызове. стек, идущий в обратном направлении от конца к началу. Она может быть в функции C (ближайшей к исключению), в функции B (чуть дальше), в функции A или даже на верхнем уровне программы, где мы вызывали функцию A.

Если Python находит подходящий блок exclude, он выполняет код в этом блоке. Если он не находит его, Python обрабатывает исключение самостоятельно. Это означает, что он напечатает исключение и выйдет из программы, так как не знает, что с ним делать.

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

Перехват исключений с помощью try, кроме

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

Простой пример

Сначала рассмотрим простой пример. Как вы, надеюсь, знаете, мы не можем делить на ноль. Если мы все равно это сделаем, Python выдаст исключение с именем 9.0003 ZeroDivisionError , который является подклассом ArithmeticError :

 попробуйте:
    печать(2/0)
кроме ZeroDivisionError:
    print("Нельзя делить на ноль!") 

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

Также обратите внимание, что Python выводит ошибку в stderr, если вы не обрабатываете исключение самостоятельно. В крошке выше это видно, потому что вывод отображается на вкладке «Ошибка», а не на вкладке «Вывод».

Перехват IOError

Давайте попробуем другой, более распространенный пример. Ведь кто делит число на ноль, верно?

Возможны исключения при взаимодействии с внешним миром, например, при работе с файлами или сетями. Например, если вы попытаетесь открыть файл с помощью Python, но этот файл не существует, вы получите Исключение IOError . Если у вас нет доступа к файлу из-за разрешений, вы снова получите исключение IOError . Давайте посмотрим, как обрабатывать эти исключения.

Назначение

Сделайте следующее:

  1. Запустите приведенный ниже код и обратите внимание на имя файла (его не существует). Посмотрите, что происходит.
  2. Измените имя файла на файл myfile.txt и повторно запустите код. Что происходит сейчас?
Назначение try-except Python

В качестве альтернативы, вот код для копирования/вставки:

 попробуйте:
    # Открыть файл в режиме только для чтения
    с open("not_here.txt", 'r') как f:
        f.write("Привет, мир!")
кроме IOError как e:
    print("Произошла ошибка:", e) 

Ответы

В первом случае файл не найден. Вы должны получить этот вывод:

 Произошла ошибка: [Errno 2] Нет такого файла или каталога: 'not_here.txt' 

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

 Произошла ошибка: недоступно для записи 

Хотя это и ошибка, она не записывается в вывод stderr операционной системы. Это потому, что мы сами обработали исключение. Если вы полностью удалили try.., кроме кода, а затем попытались записать в файл в режиме только для чтения, Python поймает ошибку, заставит программу завершиться и покажет это сообщение:

 Traceback (последний вызов последний):
  Файл «tryexcept.py», строка 3, в 
    f.write("Привет, мир!")
io.UnsupportedOperation: недоступно для записи 

Блоки finally и else

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

Блок finally в try-except

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

Вот пример этого на работе, в котором мы открываем файл без использования инструкции with , заставляя нас закрыть его самостоятельно:

 попробуйте:
    # Открыть файл в режиме записи
    f = открыть ("мой файл.txt", 'w')
    f.write("Привет, мир!")
кроме IOError как e:
    print("Произошла ошибка:", e)
окончательно:
    print("Закрытие файла сейчас")
    f.close() 

Вы также можете попробовать этот интерактивный пример:

Вы должны увидеть на экране сообщение «Закрытие файла сейчас». Теперь измените режим письма на «r» вместо «w». Вы получите сообщение об ошибке, так как файл не существует. Несмотря на это исключение, мы все равно пытаемся закрыть файл благодаря блоку finally. Это, в свою очередь, тоже идет не так: NameError  вызвано исключение, поскольку файл никогда не открывался и, следовательно, f  не существует. Это можно исправить с помощью вложенной попытки .. кроме NameError . Попробуйте сами.

Блок else в try-except

В дополнение к блокам , кроме , и , finally , вы можете добавить блок else. Блок else выполняется только тогда, когда не возникает никаких исключений. Таким образом, он отличается от блока finally тем, что finally выполняется, даже если возникает исключение.

Когда следует использовать блок else ? И почему бы вам просто не добавить дополнительный код в блок try ? Хорошие вопросы!

Согласно руководству по Python, лучше использовать предложение else, чем добавлять дополнительный код в предложение try. Но почему? Причина в том, что это позволяет избежать случайного перехвата исключения, которое не было вызвано кодом, защищенным операторами try и exclude. Я признаю, что сам не очень часто использую блоки else. Кроме того, я нахожу их несколько запутанными, особенно для людей, говорящих на других языках.

Общие исключения Python

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

Имя исключения Когда вы столкнетесь с ним Пример ситуации, вызывающей исключение
SyntaxError Возникает при наличии ошибка в синтаксисе Python. Если это исключение не будет перехвачено, это приведет к выходу интерпретатора Python. pritn('test')
KeyError Возникает, когда ключ не найден в словаре. d = { 'a': 1}
d['b']
IndexError Возникает, когда индекс выходит за пределы диапазона. lst = [1, 2, 3]
lst[10]
KeyboardInterrupt Возникает, когда пользователь нажимает клавишу прерывания (Ctrl+C) Нажатие control+c 9 0219
Некоторые общие исключения, с которыми вы столкнетесь в какой-то момент своей карьеры

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

Рекомендации по работе с исключениями

Теперь, когда мы знаем механизм обработки исключений, я хотел бы поделиться с вами несколькими рекомендациями.

Не использовать пробел, кроме блоков

Я писал об этом в блоге «Как не обрабатывать исключения в Python». Не используйте пустой блок, если хотите отловить широкий диапазон исключений. Под этим я подразумеваю что-то вроде:

 попробовать:
    ...
кроме:
    print("Произошла ошибка:") 

Вы можете встретить это в примерах кода в Интернете. Если вы это сделаете, сделайте привычкой улучшать обработку исключений. Зачем вам это нужно и как вы можете улучшить код, подобный приведенному выше примеру?

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

Итак, хотя синтаксис разрешен, я не рекомендую его. Например, вы также поймаете KeyboardInterrupt 9.0004 и Исключения SystemExit , препятствующие выходу вашей программы. Вместо этого используйте блок try со списком явных исключений, которые, как вы знаете, вы можете обработать. Или, если очень нужно, ловите базовый класс Exception для обработки почти всех обычных исключений, но не системных.

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

 from time import sleep
пока верно:
    пытаться:
        print("Попробуй остановить меня")
        спать(1)
    кроме:
        print("Не останавливай меня сейчас, я так хорошо провожу время!") 

Возможно, вам придется закрыть терминал, чтобы остановить эту программу. Теперь измените блок exclude, чтобы поймать Exception . Вы по-прежнему будете перехватывать почти все исключения, но программа завершится при системных исключениях, таких как KeyboardInterrupt и SystemExit :

 из time import sleep
пока верно:
    пытаться:
        print("Попробуй остановить меня")
        спать(1)
    кроме исключения:
        print("Что-то пошло не так") 

Лучше попросить прощения

В Python часто можно встретить шаблон, в котором люди просто пробуют, работает ли что-то, а если нет, перехватывают исключение. Другими словами, лучше попросить прощения, чем разрешения. Это отличается от других языков, где вы предпочтительно спрашиваете разрешения. Например, в Java исключения могут замедлить вашу программу, и вы «спрашиваете разрешения», выполняя проверки объекта, а не просто пытаясь.

Чтобы сделать это более конкретным: в Python мы часто просто пытаемся получить доступ к ключу в словаре. Если ключ не существует, мы получим исключение и обработаем его. Предположим, мы только что преобразовали какой-то предоставленный извне JSON в словарь и теперь начинаем его использовать:

 импорт json
user_json = '{"имя": "Джон", "возраст": 39}'
пользователь = json.loads(user_json)
пытаться:
    печать (пользователь ['имя'])
    печать (пользователь ['возраст'])
    печать (пользователь ['адрес'])
    ...
кроме KeyError как e:
    print("В пользовательском объекте отсутствуют поля: ", e)
    # Правильно обработайте ошибку
    ... 

Это напечатает ошибку:

 В пользовательском объекте отсутствуют поля: «адрес» 

Мы могли бы добавить три проверки ( , если «имя» в пользователе , , если «возраст» в пользователе и т. д.), чтобы убедиться, что все поля есть. Но это не очень хорошая практика. Это потенциально вводит много кода только для проверки существования ключей. Вместо этого мы просим прощения в блоке exclude, который намного чище и читабельнее. И если вы беспокоитесь о производительности: исключения не занимают столько циклов ЦП в Python. Многие сравнения на самом деле медленнее, чем перехват одного исключения (если оно вообще происходит!).

Создание пользовательских исключений

Все встроенные исключения, не выходящие из системы, являются производными от Класс исключения , как мы узнали ранее. Все пользовательские исключения также должны быть производными от этого класса. Поэтому, если мы хотим создать свои собственные исключения, нам нужно создать подкласс класса Exception .

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

 class UserNotFoundError(Exception):
    пройти 

Он наследует все свойства и методы класса Exception , но мы даем ему новое имя, чтобы отличать его от класса Exception . Таким образом, мы сможем специально поймать его с помощью блока исключений.

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

Мы будем использовать этот класс в следующем примере.

Вызов (или генерация) исключений

Мы знаем некоторые встроенные исключения и знаем, как создавать собственные исключения. Мы также знаем, как перехватывать исключения с помощью try и exclude. Осталось то, что называется возбуждением или выдачей исключения. Вы можете сами вызвать исключение с помощью ключевого слова повышения.

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

 класс UserNotFoundError (Исключение):
    проходить
защита fetch_user (user_id):
    # Здесь вы должны получить данные из какой-либо БД, например:
    # пользователь = db.get_user(user_id)
    # Чтобы сделать этот пример работоспособным, установим его в None
    пользователь = нет
    если пользователь == Нет:
        поднять UserNotFoundError (f'Пользователь {user_id} не в базе данных')
    еще:
        вернуть пользователя
пользователи = [123, 456, 789]
для user_id в пользователях:
    пытаться:
        fetch_user (user_id)
    кроме UserNotFoundError как e:
        print("Произошла ошибка: ", e) 
Присвоение

Вот небольшое задание. Вместо этого мы могли бы использовать обычный объект Exception. Таким образом, нам не нужно определять пользовательский. Почему это плохая идея?

Ответ

На самом деле вы можете вызвать обычное исключение, например. с поднять исключение («Пользователь не найден») . Но если вы это сделаете, вам нужно перехватить все исключения типа Exception. А их, как известно, немало. Скорее всего, вы непреднамеренно поймаете какое-то другое исключение, которое не сможете обработать. Например, клиент базы данных может выдать DatabaseAuthenticationError , который также является подклассом Exception .

Как распечатать исключение Python

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

 try:
    . ..
кроме Исключения как e:
    print("Произошла ошибка: ", e) 

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

 трассировка импорта
пытаться:
    ...
кроме исключения:
    traceback.print_exc()
 

Продолжайте учиться

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

  • Статья в моем блоге «Как не обрабатывать исключения в Python»
  • Введение в функции Python
  • Объекты и классы и наследование Python
  • Официальная документация по исключениям.
  • Официальная документация по ошибкам.

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

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

Обработка исключений в Python (попробуйте, кроме, иначе, наконец)

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

  • 8. Ошибки и исключения — обработка исключений — документация по Python 3.11.3
  • 8. Составные операторы — оператор try — документация по Python 3.11.3
Contents

  • Базовая обработка исключений в Python: try . .. кроме ...
  • Перехват нескольких исключений
    • Применение различных операций к нескольким исключениям
    • Применить одну и ту же операцию к нескольким исключениям
  • Поймать все исключения
    • Подстановочный знак, кроме (Голые кроме)
    • Базовый класс: Исключение
  • Выполнить действие, если исключения не возникло: попробуй... кроме... иначе...
  • Действие очистки: попробовать... кроме... наконец...
  • Игнорировать исключения: пройти
  • Практический пример: чтение файлов изображений

Базовая обработка исключений в Python:

try ... кроме ...

Например, при попытке деления на ноль возникает ошибка ZeroDivisionError , что приводит к завершению процесса.

 # печать (1 / 0)
# ZeroDivisionError: деление на ноль
 

источник: exception_handling.py

Чтобы перехватить это исключение, напишите следующий код:

 попробуйте:
    печать (1 / 0)
кроме ZeroDivisionError:
    распечатать('Ошибка')
# Ошибка
 

источник: exception_handling. py

При использовании , кроме <имя-исключения> как <имя-переменной>: , объект исключения сохраняется в переменной. Вы можете выбрать любое имя для переменной, но обычно используются такие имена, как e и err .

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

 попробуйте:
    печать (1 / 0)
кроме ZeroDivisionError как e:
    печать (е)
    печать (тип (е))
# деление на ноль
# <класс 'ZeroDivisionError'>
 

источник: exception_handling.py

В Python 2 это должно быть записано как кроме <имя-исключения>, <имя-переменной>: .

Можно также указать базовый класс. Например, ArithmeticError является базовым классом для ZeroDivisionError . Переменная хранит объект исключения производного класса, который действительно произошел.

 печать (issubclass (ZeroDivisionError, ArithmeticError))
# Истинный
пытаться:
    печать (1 / 0)
кроме ArithmeticError как e:
    печать (е)
    печать (тип (е))
# деление на ноль
# <класс 'ZeroDivisionError'>
 

источник: exception_handling. py

Проверьте официальную документацию для встроенных исключений в Python.

  • Встроенные исключения — Документация по Python 3.9.0

При возникновении исключения в предложении try последующий процесс в предложении try пропускается.

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

 попробуйте:
    для i в [-2, -1, 0, 1, 2]:
        печать (1 / я)
кроме ZeroDivisionError как e:
    печать (е)
# -0,5
# -1.0
# деление на ноль
 

источник: exception_handling.py

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

Перехват нескольких исключений

Определите следующую функцию, которая перехватывает ZeroDivisionError .

 по умолч. разделить(а, б):
    пытаться:
        печать (а / б)
    кроме ZeroDivisionError как e:
        print('поймать ZeroDivisionError:', e)
 

источник: exception_handling.py

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

 разделить(1, 0)
# поймать ZeroDivisionError: деление на ноль
# разделить('а', 'б')
# TypeError: неподдерживаемые типы операндов для /: 'str' и 'str'
 

источник: exception_handling.py

Применение разных операций к нескольким исключениям

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

 по определению разделитель_каждый (а, б):
    пытаться:
        печать (а / б)
    кроме ZeroDivisionError как e:
        print('поймать ZeroDivisionError:', e)
    кроме TypeError как e:
        print('поймать TypeError:', e)
разделить_каждый (1, 0)
# поймать ZeroDivisionError: деление на ноль
разделить_каждый ('а', 'б')
# поймать TypeError: неподдерживаемые типы операндов для /: 'str' и 'str'
 

источник: exception_handling. py

Применить одну и ту же операцию к нескольким исключениям

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

 по определению разделите_то же (а, б):
    пытаться:
        печать (а / б)
    кроме (ZeroDivisionError, TypeError) как e:
        печать (е)
разделить_то же (1, 0)
# деление на ноль
разделить_то же ('а', 'б')
# неподдерживаемые типы операндов для /: 'str' и 'str'
 

источник: exception_handling.py

Перехватывать все исключения

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

Подстановочный знак, кроме (Голое исключение)

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

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

В последнем предложении exclude можно опускать имена исключений, чтобы они служили подстановочными знаками. Используйте это с особой осторожностью, так как таким образом легко замаскировать настоящую ошибку программирования! 8. Ошибки и исключения — обработка исключений — документация по Python 3.9.0

 по определению разделитель подстановочных знаков (а, б):
    пытаться:
        печать (а / б)
    кроме:
        распечатать('Ошибка')
разделить_подстановочный знак (1, 0)
# Ошибка
Division_wildcard ('а', 'б')
# Ошибка
 

источник: exception_handling.py

Использование подстановочного знака, кроме всех исключений, включая SystemExit (вызвано sys.exit() и т. д.) и KeyboardInterrupt (вызвано при нажатии клавиши прерывания Ctrl + C ).

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

Базовый класс:

Exception

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

  • Встроенные исключения — Исключение — Документация по Python 3.11.3
 по определению разделять_исключение (а, б):
    пытаться:
        печать (а / б)
    кроме Исключения как e:
        печать (е)
разделить_исключение (1, 0)
# деление на ноль
разделить_исключение ('а', 'б')
# неподдерживаемые типы операндов для /: 'str' и 'str'
 

источник: exception_handling.py

Иерархия классов для встроенных исключений выглядит следующим образом.

  • Встроенные исключения — иерархия исключений — Документация по Python 3.11.3
 Исключение базы
 ├── BaseExceptionGroup
 ├── ГенераторВыход
 ├── Прерывание Клавиатуры
 ├── Выход из системы
 └── Исключение
      ├── StopAsyncIteration
      ├── Остановить итерацию
      ├── . ..
       ...
 

Поскольку SystemExit и KeyboardInterrupt не наследуют Exception , указание Exception в предложении , кроме , не будет перехватывать sys.exit() и исключение ввода клавиши прерывания.

Это исключение вызывается функцией sys.exit(). Он наследуется от BaseException, а не от Exception, поэтому он не может быть случайно перехвачен кодом, который перехватывает Exception. Это позволяет исключению правильно распространяться и вызывать выход интерпретатора. Встроенные исключения — SystemExit — Документация по Python 3.11.3

Возникает, когда пользователь нажимает клавишу прерывания (обычно Control-C или Delete). Во время выполнения регулярно выполняется проверка прерываний. Исключение наследуется от BaseException, чтобы не быть случайно перехваченным кодом, который перехватывает Exception и, таким образом, предотвращает выход интерпретатора. Встроенные исключения — KeyboardInterrupt — Документация по Python 3.11.3

Базовый класс для всех встроенных исключений, включая SystemExit и KeyboardInterrupt , — BaseException . Если вы укажете BaseException вместо Exception в предложении , кроме , будут перехвачены все исключения, а также подстановочные знаки, кроме.

  • Встроенные исключения — BaseException — Документация по Python 3.11.3

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

Выполнить действие, если исключения не возникло:

try...except...else...

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

 по определению разделите_еще (а, б):
    пытаться:
        печать (а / б)
    кроме ZeroDivisionError как e:
        print('поймать ZeroDivisionError:', e)
    еще:
        print('Готово (без ошибок)')
разделить_еще (1, 2)
# 0,5
# закончить (без ошибок)
разделить_еще (1, 0)
# поймать ZeroDivisionError: деление на ноль
 

источник: exception_handling.py

Действие очистки:

try ... кроме ... finally ...

происходит исключение или нет.

 по определению разделите_наконец(а, б):
    пытаться:
        печать (а / б)
    кроме ZeroDivisionError как e:
        print('поймать ZeroDivisionError:', e)
    окончательно:
        распечатать('все готово')
разделить_наконец (1, 2)
# 0,5
# все готово
разделить_наконец (1, 0)
# поймать ZeroDivisionError: деление на ноль
# все готово
 

источник: exception_handling.py

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

 по определению разделять_еще_наконец (а, б):
    пытаться:
        печать (а / б)
    кроме ZeroDivisionError как e:
        print('поймать ZeroDivisionError:', e)
    еще:
        print('Готово (без ошибок)')
    окончательно:
        распечатать('все готово')
разделить_еще_наконец(1, 2)
# 0,5
# закончить (без ошибок)
# все готово
разделить_еще_наконец (1, 0)
# поймать ZeroDivisionError: деление на ноль
# все готово
 

источник: exception_handling.py

Игнорировать исключения:

pass

Если вы хотите перехватить исключение и продолжить без каких-либо действий, используйте pass .

 по определению разделитель_перехода (а, б):
    пытаться:
        печать (а / б)
    кроме ZeroDivisionError:
        проходить
разделить_проход (1, 0)
 

источник: exception_handling.py

Дополнительные сведения об инструкции pass см. в следующей статье.

  • Оператор pass в Python

Практический пример: чтение файлов изображений

Удобным примером использования обработки исключений является чтение файлов изображений.

Ниже приведен пример изменения размера файлов изображений в папке с помощью Pillow.

  • Изменение размера изображений с помощью Python, Pillow

Без обработки исключений:

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

  • Получить имя файла, каталог, расширение из строки пути в Python
  • Оператор in в Python (для списка, строки, словаря и т. д.)
 импорт ОС
импортировать глобус
из изображения импорта PIL
dst_dir = 'data/temp/images_half'
os.makedirs (dst_dir, exists_ok = True)
 

источник: Pillow_image_resize_all.py

 files = glob.glob('./data/temp/images/*')
для f в файлах:
    root, ext = os.path.splitext(f)
    если расширение в ['.jpg', '.png']:
        img = Image.open(f)
        img_resize = img.resize((img.width // 2, img.height // 2))
        базовое имя = os.path.basename(root)
        img_resize. save(os.path.join(dst_dir, basename + '_half' + ext))
 

источник: Pillow_image_resize_all.py

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

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

 files = glob.glob('./data/temp/images/*')
для f в файлах:
    пытаться:
        img = Image.open(f)
        img_resize = img.resize((img.width // 2, img.height // 2))
        root, ext = os.path.splitext(f)
        базовое имя = os.path.basename(root)
        img_resize.save(os.path.join(dst_dir, basename + '_half' + ext))
    кроме OSError как e:
        проходить
 

источник: Pillow_image_resize_all.py

Размер всех файлов, которые можно открыть с помощью Pillow Image.open() , изменен.

Подход, который явно проверяет условия, как и в первом примере, называется «LBYL: Look Before You Leap», а подход, использующий обработку исключений, как и во втором примере, называется «EAFP: проще запрашивать Прощение, чем разрешение».