Овладейте всеми знаниями об обработке исключений Python в одной статье

Python

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

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

1. Ошибка

Со стороны программного обеспечения ошибка может быть синтаксической или логической. Ошибки бывают грамматическими или логическими.

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

Когда синтаксис программы правильный, остальное — логическая ошибка. Логические ошибки могут быть вызваны неполным или неправильным вводом;

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

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

2. Исключение

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

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

Первый этап возникает после возникновения исключительного состояния (иногда называемого исключительным состоянием).

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

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

Текущий поток будет прерван для обработки этой ошибки и принятия соответствующих мер. Это второй этап.

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

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

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

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

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

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

Для перехвата исключений можно использовать операторы try/except.

Оператор try/except используется для обнаружения ошибок в блоке операторов try, чтобы оператор exclude собирал и обрабатывал информацию об исключении.

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

грамматика:

Ниже приведен синтаксис простого try....except...else:

try:
<语句>        #运行别的代码
except <名字>:
<语句>        #如果在try部份引发了'name'异常
except <名字>,<数据>:
<语句>        #如果引发了'name'异常,获得附加的数据
else: 
<语句>        #如果没有异常发生

Как работает Try, так это то, что когда вы запускаете оператор try, python помечает его в контексте текущей программы, чтобы вы могли вернуться сюда, когда возникает исключение, предложение try выполняется первым, а то, что происходит дальше, зависит от времени выполнения. происходит исключение.

  1. Если при выполнении инструкции после попытки возникает исключение, python переходит обратно к попытке и выполняет первое предложение исключения, которое соответствует исключению, и после обработки исключения управление проходит через весь оператор попытки (если не возникает новое исключение). выбрасывается во время обработки исключения).
  2. Если в операторе, следующем за попыткой, возникает исключение, но нет соответствующего предложения исключения, исключение будет передано на более высокий уровень попытки или на верхний уровень программы (что завершит программу и напечатает сообщение об ошибке по умолчанию). .
  3. Если при выполнении предложения try не возникает исключения, python выполняет оператор, следующий за оператором else (если есть else), а затем управление передается через оператор try.

Использовать, кроме как без какого-либо типа исключения

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

try:
正常的操作
......................
except:
发生异常则执行此处代码
......................
else:
没有异常则执行此处代码

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

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

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

try:
正常的操作
......................
except(Exception1[, Exception2[,...ExceptionN]]]):
发生以上多个异常中的一个,执行这块代码
......................
else:
如果没有异常执行这块代码

оператор try-finally

Оператор try-finally выполняет окончательный код независимо от того, возникает ли исключение.

try:
<语句>
finally:
<语句>    #退出try时总会执行
raise

Когда в блоке try генерируется исключение, код блока finally выполняется немедленно.

После того, как все операторы в блоке finally выполнены, снова возникает исключение и выполняется код блока exclude.

Содержимое параметра отличается от исключения.

Давайте посмотрим на пример:

def div(a, b):
try:
print(a / b)
except ZeroDivisionError:
print("Error: b should not be 0 !!")
except Exception as e:
print("Unexpected Error: {}".format(e))
else:
print('Run into else only when everything goes well')
finally:
print('Always run into finally block.')

# tests
div(2, 0)
div(2, 'bad type')
div(1, 2)

# Mutiple exception in one line
try:
print(a / b)
except (ZeroDivisionError, TypeError) as e:
print(e)

# Except block is optional when there is finally
try:
open(database)
finally:
close(database)

# catch all errors and log it
try:
do_work()
except:    
# get detail from logging module
logging.exception('Exception caught!')

# get detail from sys.exc_info() method
error_type, error_value, trace_back = sys.exc_info()
print(error_value)
raise

Обобщенно следующим образом:

  1. Оператор exception не нужен, и оператор finally не нужен, но должен быть один из двух, иначе попытка не имеет смысла.
  2. Операторов исключений может быть несколько. Python будет сопоставлять исключения, которые вы укажете, в порядке операторов исключений. Если исключение было обработано, он не будет вводить следующие операторы исключения.
  3. Оператор exclude может указывать несколько исключений одновременно в виде кортежей, см. пример кода.
  4. Если тип исключения не указан после оператора exclude, по умолчанию перехватываются все исключения.Текущее исключение можно получить с помощью ведения журнала или модуля sys.
  5. Если вы хотите поймать исключение, а затем повторно его генерировать, используйте повышение без каких-либо аргументов или информации.
  6. Не рекомендуется перехватывать и выдавать одно и то же исключение, рассмотрите возможность рефакторинга кода.
  7. Не рекомендуется отлавливать все исключения, не зная логики, возможно, вы скрываете серьезную проблему.
  8. Попробуйте заменить операторы try/except встроенными операторами обработки исключений, такими как оператор with и метод getattr().

Кейс с опытом

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

def f1():
print(1/0)
def f2():
try:
f1()
except Exception as e:
raise # don't raise e !!!
f2()

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

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

def f2():
try:
f1()
except Exception as e:
e.args += ('more info',)
raise

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

Исключение и базовое исключение

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

BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration...
+-- StandardError...
+-- Warning...

С точки зрения иерархии исключений BaseException является самым основным классом исключений, и Exception наследует его. Помимо всех исключений, BaseException также включает три исключения SystemExit, KeyboardInterrupt и GeneratorExit.

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

кроме Exception как e и кроме Exception, e

Пример кода выглядит следующим образом:

try:
do_something()
except NameError as e:  # should
pass
except KeyError, e:  # should not
pass

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

поднять "строку исключения"

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

if is_work_done():
pass
else:
raise "Work is not done!" # not cool

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

Traceback (most recent call last):
File "/demo/exception_hanlding.py", line 48, in <module>
raise "Work is not done!"
TypeError: exceptions must be old-style classes or derived from BaseException, not str

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

Используйте встроенные шаблоны синтаксиса вместо try/except

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

Оператор with автоматически вызывает операцию закрытия файла в finally после открытия файла. Когда мы пишем код Python, мы должны стараться избегать использования try/except/finally, чтобы справиться с этой ситуацией.

# should not
try:
f = open(a_file)
do_something(f)
finally:
f.close()
# should 
with open(a_file) as f:
do_something(f)

В качестве другого примера, когда нам нужно получить доступ к неопределенному свойству, вероятно, вы напишете такой код:

try:
test = Test()
name = test.name  # not sure if we can get its name
except AttributeError:
name = 'default'

На самом деле вы можете использовать более простой метод getattr() для своих целей.

Лучшие практики

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

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

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

3. Избегайте бессмысленных действий в блоке catch.

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

5. При необходимости не забудьте использовать finally для освобождения ресурсов.

6 При необходимости не забудьте сделать очистку или откат после обработки исключений.

Шпаргалка


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

[Суперполная отделка] «Всесторонняя разработка автоматизации Python от начального уровня до мастерства», примечания к базовому учебному пособию по python