Должен ли я всегда указывать тип исключения в операторах ʻexcept`?

96

При использовании PyCharm IDE использование типа except:без исключения вызывает напоминание от IDE о том, что это предложение исключения Too broad.

Стоит ли игнорировать этот совет? Или Pythonic всегда определяет тип исключения?

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

Ответы:

93

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

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

try:
    insert(connection, data)
except:
    update(connection, data)

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

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

Следствием всего этого является то, что ваш код никогда не должен работать, raise Exception('some message')потому что он заставляет использовать клиентский код except:(или except Exception:что почти так же плохо). Вы должны определить исключение, специфичное для проблемы, о которой хотите сообщить (возможно, унаследовав от некоторого встроенного подкласса исключений, например ValueErrorили TypeError). Или вы должны вызвать конкретное встроенное исключение. Это позволяет пользователям вашего кода быть осторожными при отлове только тех исключений, которые они хотят обработать.

баббидж
источник
7
+1 Совершенно верно. Еще больше удовольствия с примером: except:также улавливает (среди многих других вещей) NameErrorи AttributeError, поэтому, если вы неправильно написали что-то в tryблоке (например, ваша функция "вставить" на самом деле вызывается, insert_oneпотому что кто-то не ценит согласованность так, как должен), она всегда молча пытается update().
1
Так что насчет того, когда вам нужно убедиться, что исключение не возникает выше текущего сайта вызова? Т.е. - я поймал все конкретные исключения, которые, как я могу предвидеть, будут выброшены, теперь мне нужно добавить, что «если эта вещь, о которой я не думал, будет выброшена, мне нужно зарегистрировать ее, прежде чем она убьет текущий контекст выполнения» (например, main())?
Адам Паркин,
Это та ситуация, о которой я говорю в абзаце, начинающемся «Один случай ...». Иногда это определенно необходимо, но в любой программе действительно должно быть только одно место, которое это делает. И вам нужно быть осторожным, чтобы в журнале было ясно, что происходит, иначе у вас будет неприятное время, пытаясь понять, почему ваша программа не обрабатывает событие / запрос / что-либо правильно.
babbageclunk
3
@delnan: Хуже того. except Exception:поймают NameErrorи AttributeErrorтоже. Что делает bare except:настолько плохим, так это то, что он улавливает вещи, которые не имеют никакого отношения к ловле, например SystemExit(поднимается, когда вы звоните exitили sys.exit, и теперь вы предотвратили предполагаемый выход) и KeyboardInterrupt(опять же, если пользователь ударил Ctrl-C, вы, вероятно, не захотите продолжать бежать им назло). Только последнее имеет смысл ловить, и его следует ловить явно. По крайней мере, except Exception:позволяет этим двум нормально размножаться.
ShadowRanger
39

Вы не должны игнорировать советы, которые дает вам переводчик.

Из Руководства по стилю PEP-8 для Python:

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

Например, используйте:

 try:
     import platform_specific_module 
 except ImportError:
     platform_specific_module = None 

Пустое предложение except: перехватит исключения SystemExit и KeyboardInterrupt, что затруднит прерывание программы с помощью Control-C и может замаскировать другие проблемы. Если вы хотите перехватить все исключения, которые сигнализируют об ошибках программы, используйте except Exception: (bare except эквивалентно except BaseException :).

Хорошее практическое правило - ограничить использование пустых предложений "за исключением" двумя случаями:

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

ашишр
источник
9

Это не относится к Python.

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

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

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

Если вы поставите try catch вокруг этого, то независимо от того, какая проблема была в вашей файловой процедуре (только чтение, разрешения, UAC, на самом деле не pdf и т. Д.), Каждый из них попадет в ваш файл, не найденный улов, и ваш пользователь кричит "но он там, этот код дерьмо"

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

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

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

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

Тони Хопкинсон
источник
Я бы сказал, что это баланс. Вы должны поймать исключение достаточно рано, чтобы иметь возможность оправиться от него, и достаточно поздно, чтобы знать, что с ним делать. Вот почему обработка исключений Java вызывает такой хаос, потому что вам нужно заново обернуть исключение на каждом шаге, и вы потеряете информацию.
dhill
2
+1 за «вам все равно, почему все пошло не так». Я использую его в нескольких местах вокруг одной строки кода, где я анализирую дату / время из URL-адреса. Сторонняя библиотека анализа даты / времени не перечисляет все исключения, которые она может генерировать (я нашел OverflowError и TypeError в дополнение к стандартному ValueError, но их, вероятно, больше), и в любом случае мне действительно все равно, почему было выбрано исключение, я просто хочу предоставить пользователю разумное сообщение об ошибке, говорящее, что что-то не так с датой / временем.
Майкл Родби 07
3

Вы также поймаете, например, Control-C с этим, так что не делайте этого, пока вы не "бросите" его снова. Однако в этом случае лучше использовать «наконец».

Ульрих Экхардт
источник
3

Всегда указывайте тип исключения, есть много типов, которые вы не хотите перехватывать, например SyntaxError, KeyboardInterruptи MemoryErrorт. Д.

Павел Аносов
источник
2
может ли использование except Exception:избежать перечисленных выше типов, которые мы не хотим ловить?
HorseloverFat
except ExceptionЭто хорошо.
Ульрих Экхардт
4
@HorseloverFat: except Exceptionловит SyntaxErrorи MemoryErrorпотому, что это их базовый класс. KeyboardInterrupt, SystemExit(поднятые sys.exit()) не улавливаются (они являются непосредственными подклассами BaseException)
jfs
звучит так, как будто это не идеально - лучше уточнить точнее.
HorseloverFat
3

Вот места, где я использую, кроме без типа

  1. быстрое и грязное прототипирование

Это основное использование в моем коде непроверенных исключений

  1. функция верхнего уровня main (), где я регистрирую каждое неперехваченное исключение

Я всегда добавляю это, чтобы производственный код не проливал следы стека

  1. между уровнями приложения

У меня есть два способа сделать это:

  • Первый способ сделать это: когда более высокий уровень вызывает функцию более низкого уровня, он оборачивает вызовы в типизированные исключения для обработки исключений «верхнего» нижнего уровня. Но я добавляю общий оператор except для обнаружения необработанных исключений нижнего уровня в функциях нижнего уровня.

Я предпочитаю этот способ, мне легче определить, какие исключения должны были быть перехвачены надлежащим образом: я «вижу» проблему лучше, когда исключение более низкого уровня регистрируется более высоким уровнем

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

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

нипил
источник
-14

Попробуй это:

try:
    #code
except ValueError:
    pass

Я получил ответ по этой ссылке, если кто-то еще столкнется с этой проблемой, проверьте это

Mekanic
источник