Я часто вижу комментарии к другим вопросам переполнения стека о том, как except: pass
не рекомендуется использовать. Почему это плохо? Иногда мне просто все равно, что это за ошибки, и я просто хочу продолжить с кодом.
try:
something
except:
pass
Почему использование except: pass
блока плохо? Что делает это плохо? Это тот факт, что я pass
ошибаюсь или я except
ошибаюсь?
logging
модуль на уровне DEBUG, чтобы избежать их использования в производственной среде, но оставляйте их в разработке.Ответы:
Как вы правильно догадались, у этого есть две стороны: перехватывать любую ошибку, не указывая тип исключения после
except
, и просто передав ее без каких-либо действий.Мое объяснение «немного» длиннее - так что д-р разбивается на следующее:
Но давайте углубимся в детали:
Не лови ни одной ошибки
При использовании
try
блока вы обычно делаете это, потому что знаете, что есть вероятность возникновения исключения. Таким образом, у вас также уже есть приблизительное представление о том, что может сломаться и какое исключение может быть выдано. В таких случаях вы ловите исключение, потому что вы можете восстановить после него. Это означает, что вы подготовлены к исключению и имеете какой-то альтернативный план, которому вы будете следовать в случае этого исключения.Например, когда вы просите пользователя ввести число, вы можете преобразовать ввод, используя
int()
который может вызвать aValueError
. Вы можете легко восстановить это, просто попросив пользователя повторить попытку, поэтому перехватValueError
и повторный запрос пользователя будут подходящим планом. Другой пример - если вы хотите прочитать какую-то конфигурацию из файла, а этот файл не существует. Поскольку это файл конфигурации, у вас может быть некоторая конфигурация по умолчанию в качестве запасного варианта, поэтому файл не является абсолютно необходимым. Так что пойматьFileNotFoundError
и просто применить конфигурацию по умолчанию было бы хорошим планом здесь. Теперь в обоих этих случаях у нас есть очень конкретное исключение, которое мы ожидаем, и у нас есть одинаково конкретный план восстановления после него. Таким образом , в каждом конкретном случае, мы явно толькоexcept
что определенные исключение.Однако, если бы нам нужно было все поймать , то - в дополнение к тем исключениям, от которых мы готовы восстанавливаться, - также есть шанс, что мы получим исключения, которые мы не ожидали и от которых мы действительно не можем восстановить; или не должен оправляться от.
Давайте рассмотрим пример файла конфигурации сверху. В случае отсутствия файла мы просто применили нашу конфигурацию по умолчанию и на более позднем этапе могли бы решить автоматически сохранить конфигурацию (поэтому в следующий раз файл будет существовать). Теперь представьте, что мы получаем
IsADirectoryError
илиPermissionError
вместо. В таких случаях мы, вероятно, не хотим продолжать; мы все еще можем применить нашу конфигурацию по умолчанию, но позже мы не сможем сохранить файл. И вполне вероятно, что пользователь хотел иметь собственную конфигурацию, поэтому использование значений по умолчанию, скорее всего, нежелательно. Поэтому мы бы хотели немедленно сообщить об этом пользователю и, возможно, прервать выполнение программы. Но это не то, что мы хотим сделать где-то глубоко внутри какой-то небольшой части кода; это что-то важное на уровне приложения, поэтому его нужно обрабатывать наверху, поэтому пусть возникнет исключение.Другой простой пример также упоминается в документе идиом Python 2 . Здесь в коде существует простая опечатка, которая приводит к ее поломке. Поскольку мы ловим каждое исключение, мы также ловим
NameError
s иSyntaxError
s . Обе ошибки случаются со всеми нами во время программирования; и обе эти ошибки мы абсолютно не хотим включать при отправке кода. Но поскольку мы также поймали их, мы даже не узнаем, что они там произошли, и потеряем какую-либо помощь для их правильной отладки.Но есть и более опасные исключения, к которым мы вряд ли готовы. Например, SystemError - это обычно то, что случается редко и что мы не можем планировать; это означает, что происходит что-то более сложное, что, скорее всего, мешает нам продолжать текущую задачу.
В любом случае, очень маловероятно, что вы подготовлены ко всему в небольшой части кода, поэтому на самом деле вы должны ловить только те исключения, к которым вы подготовлены. Некоторые люди предлагают по крайней мере поймать,
Exception
поскольку это не будет включать в себя такие вещи, какSystemExit
иKeyboardInterrupt
которые по замыслу должны прекратить ваше приложение, но я бы сказал, что это все еще слишком неопределенно. Есть только одно место, где я лично принимаю ловлюException
или просто любоеисключение, и это в едином глобальном обработчике исключений уровня приложения, который имеет единственную цель - записать любое исключение, к которому мы не были подготовлены. Таким образом, мы все еще можем хранить как можно больше информации о непредвиденных исключениях, которые мы затем можем использовать для расширения нашего кода, чтобы обрабатывать их явно (если мы сможем восстановить их) или - в случае ошибки - для создания тестовых случаев, чтобы убедиться, это больше не повторится. Но, конечно, это работает, только если мы поймаем те исключения, которые мы уже ожидали, поэтому те, которые мы не ожидали, естественно всплывают.Старайтесь избегать прохода, кроме блоков
Если явно отлавливать небольшую подборку конкретных исключений, существует множество ситуаций, в которых мы будем в порядке, просто ничего не делая. В таких случаях просто иметь
except SomeSpecificException: pass
хорошо. Однако в большинстве случаев это не так, поскольку нам, вероятно, понадобится некоторый код, связанный с процессом восстановления (как упомянуто выше). Это может быть, например, то, что повторяет действие снова, или вместо этого установить значение по умолчанию.Если это не так, например, потому что наш код уже структурирован, чтобы повторяться до тех пор, пока он не преуспеет, тогда достаточно просто передать. Взяв наш пример сверху, мы можем попросить пользователя ввести число. Поскольку мы знаем, что пользователям нравится не делать то, о чем мы их просим, мы могли бы просто поместить это в цикл, чтобы это выглядело так:
Поскольку мы продолжаем попытки до тех пор, пока не будет выдано исключение, нам не нужно делать ничего особенного в блоке кроме, так что это нормально. Но, конечно, можно утверждать, что мы по крайней мере хотим показать пользователю какое-то сообщение об ошибке, чтобы сказать ему, почему он должен повторить ввод.
Тем не менее, во многих других случаях простое указание
except
является признаком того, что мы не были готовы к исключению, которое мы ловим. Если эти исключения не являются простыми (например,ValueError
илиTypeError
), и причина, по которой мы можем пройти, очевидна, старайтесь избегать просто передачи. Если на самом деле нечего делать (и вы абсолютно уверены в этом), подумайте над добавлением комментария, почему это так; в противном случае разверните блок исключения, чтобы фактически включить некоторый код восстановления.except: pass
Но худшим нарушителем является комбинация обоих. Это означает, что мы охотно улавливаем любую ошибку, хотя мы абсолютно не готовы к ней, и мы также ничего не делаем с этим. Вы, по крайней мере, хотите зарегистрировать ошибку, а также, вероятно, повторно вызвать ее, чтобы по-прежнему завершать работу приложения (маловероятно, что вы сможете продолжить как обычно после MemoryError). Простое прохождение, хотя и не только поддерживает приложение в некоторой степени живым (в зависимости от того, куда вы его ловите, конечно), но и отбрасывает всю информацию, делая невозможным обнаружение ошибки, что особенно верно, если вы не тот, кто ее обнаруживает.
Итак, суть в следующем: поймать только те исключения, которые вы действительно ожидаете и готовы к восстановлению; все остальные, скорее всего, либо ошибки, которые вы должны исправить, либо что-то, к чему вы все равно не готовы. Проходить определенные исключения - это хорошо, если вам действительно не нужно что-то с ними делать. Во всех остальных случаях это просто знак презумпции и ленивости. И вы определенно хотите это исправить.
источник
except
, но затем вызываютraise
без аргументов, чтобы продолжить, чтобы исключение всплыло, завершив приложение. Мне это нравится: ianbicking.org/blog/2007/09/re-raising-exceptions.html . Похоже, твердое исключение из правила о неиспользовании одеялаexcept
.raise
. Вы обычно делаете это только в нескольких местах в вашем приложении, чтобы зарегистрировать исключение.Основная проблема здесь в том, что он игнорирует все и любую ошибку: нехватка памяти, процессор горит, пользователь хочет остановить, программа хочет выйти, Jabberwocky убивает пользователей.
Это слишком много. В вашей голове вы думаете: «Я хочу игнорировать эту сетевую ошибку». Если что-то неожиданное идет не так, то ваш код молча продолжает и ломается совершенно непредсказуемым образом, который никто не может отладить.
Вот почему вы должны ограничиться тем, чтобы игнорировать только некоторые ошибки, а остальные пропустить.
источник
Выполнение вашего псевдокода буквально даже не дает никакой ошибки:
как будто это совершенно правильный кусок кода, вместо того, чтобы бросать
NameError
. Я надеюсь, что это не то, что вы хотите.источник
Это перехватывает все возможные исключения, включая
GeneratorExit
,KeyboardInterrupt
иSystemExit
- которые являются исключениями, которые вы, вероятно, не собираетесь перехватывать. Это так же, как ловитьBaseException
.Более старые версии документации гласят :
Исключительная иерархия Python
Если вы перехватываете родительский класс исключений, вы также перехватываете все их дочерние классы. Гораздо элегантнее ловить только те исключения, с которыми вы готовы справиться.
Вот иерархия исключений Python 3 - вы действительно хотите поймать их всех ?:
Не делай этого
Если вы используете эту форму обработки исключений:
Тогда вы не сможете прервать свой
something
блок с помощью Ctrl-C. Ваша программа пропустит все возможные исключения внутриtry
блока кода.Вот еще один пример, который будет иметь такое же нежелательное поведение:
Вместо этого попытайтесь поймать только определенное исключение, которое, как вы знаете, вы ищете. Например, если вы знаете, что вы можете получить ошибку значения при конвертации:
Дальнейшее объяснение с другим примером
Возможно, вы делаете это, потому что вы просматривали веб-страницы и получали, скажем, a
UnicodeError
, но поскольку вы использовали самый широкий метод отслеживания исключений, ваш код, который может иметь другие фундаментальные недостатки, будет пытаться выполнить до конца, тратя впустую пропускную способность , время обработки, износ оборудования, нехватка памяти, сбор мусора и т. д.Если другие люди просят вас завершить, чтобы они могли положиться на ваш код, я понимаю, что чувствую себя вынужденным просто справиться со всем. Но если вы готовы с шумом терпеть неудачу по мере своего развития, у вас будет возможность исправлять проблемы, которые могут возникать только периодически, но это может быть долгосрочными дорогостоящими ошибками.
Благодаря более точной обработке ошибок ваш код может быть более надежным.
источник
Итак, вот мое мнение. Всякий раз, когда вы обнаружите ошибку, вы должны сделать что-то для ее обработки, т.е. записать ее в лог-файл или что-то еще. По крайней мере, он сообщает вам, что раньше была ошибка.
источник
Вы должны использовать хотя бы,
except Exception:
чтобы избежать перехвата системных исключений, таких какSystemExit
илиKeyboardInterrupt
. Вот ссылка на документы.В общем, вы должны явно определять исключения, которые вы хотите перехватить, чтобы избежать перехвата нежелательных исключений. Вы должны знать, какие исключения вы игнорируете .
источник
Во-первых, он нарушает два принципа Zen of Python :
Это означает, что вы намеренно делаете свою ошибку молча. Более того, вы не знаете, какая именно ошибка произошла, потому что
except: pass
что поймает любое исключение.Во-вторых, если мы попытаемся абстрагироваться от дзен-питона и говорить с точки зрения здравомыслия, вы должны знать, что использование
except:pass
лишает вас знаний и контроля в вашей системе. Основное правило заключается в том, чтобы в случае ошибки вызвать исключение и предпринять соответствующие действия. Если вы заранее не знаете, какими должны быть эти действия, хотя бы зарегистрируйте ошибку где-нибудь (и лучше повторно вызовите исключение):Но, как правило, если вы пытаетесь поймать какое-либо исключение, вы, вероятно, делаете что-то не так!
источник
except:pass
Конструкция существенно заглушает любые исключительные условия , которые приходят в то время как код рассматривается вtry:
блоке бегутся.Что делает эту плохую практику то, что это обычно не то, что вы действительно хотите. Чаще всего возникает какое-то конкретное условие, которое вы хотите заставить замолчать, и
except:pass
это слишком тупой инструмент. Он выполнит свою работу, но он также замаскирует другие состояния ошибки, которые вы, вероятно, не ожидали, но, возможно, очень захотите устранить их каким-либо другим способом.Что делает это особенно важным в Python, так это то, что по идиомам этого языка исключения не обязательно являются ошибками . Конечно, они часто используются таким же образом, как и в большинстве языков. Но, в частности, Python иногда использовал их для реализации альтернативного пути выхода из некоторых задач кода, который на самом деле не является частью обычного работающего случая, но все же известно, что время от времени он возникает и может даже ожидаться в большинстве случаев.
SystemExit
уже упоминалось в качестве старого примера, но наиболее распространенным примером в настоящее время может бытьStopIteration
. Использование исключений таким образом вызвало много споров, особенно когда итераторы и генераторы были впервые представлены в Python, но в итоге идея возобладала.источник
Причина № 1 уже была указана - она скрывает ошибки, которые вы не ожидали.
(# 2) - Это делает ваш код трудным для чтения и понимания другими. Если вы перехватываете FileNotFoundException при попытке прочитать файл, то для другого разработчика будет совершенно очевидно, какой функциональностью должен обладать блок «catch». Если вы не укажете исключение, вам понадобятся дополнительные комментарии, чтобы объяснить, что должен делать блок.
(# 3) - Это демонстрирует ленивое программирование. Если вы используете универсальный try / catch, это указывает либо на то, что вы не понимаете возможных ошибок времени выполнения в вашей программе, либо на том, что вы не знаете, какие исключения возможны в Python. Поймание конкретной ошибки показывает, что вы понимаете и вашу программу, и диапазон ошибок, которые выдает Python. Это, скорее всего, заставит других разработчиков и рецензентов доверять вашей работе.
источник
Итак, что выводит этот код?
Теперь представьте
try
-except
блок сотня строк звонков в сложную иерархию объектов, и сам называются в середине вызова дерева большой программы. Когда программа идет не так, где вы начинаете искать?источник
В общем, вы можете классифицировать любую ошибку / исключение в одной из трех категорий :
Неустранимый : не ваша вина, вы не можете предотвратить их, вы не можете оправиться от них. Вы, конечно, не должны игнорировать их и продолжать и оставлять свою программу в неизвестном состоянии. Просто позвольте ошибке прекратить вашу программу, вы ничего не можете сделать.
Boneheaded : Ваша собственная ошибка, скорее всего, из-за недосмотра, ошибки или ошибки программирования. Вы должны исправить ошибку. Опять же, вы, безусловно, не должны игнорировать и продолжать.
Экзогенный : Вы можете ожидать эти ошибки в исключительных ситуациях, таких как файл не найден или соединение разорвано . Вы должны явно обрабатывать эти ошибки, и только эти.
Во всех случаях
except: pass
ваша программа останется только в неизвестном состоянии, где она может нанести больший урон.источник
Проще говоря, если выдается исключение или ошибка, что-то не так. Это может быть не совсем неправильно, но создавать, выдавать и перехватывать ошибки и исключения только ради использования операторов goto не очень хорошая идея, и это делается редко. 99% времени где-то была проблема.
Проблемы должны быть решены. Также как в жизни, в программировании, если вы просто оставляете проблемы в покое и стараетесь их игнорировать, они не просто уходят сами по себе много раз; вместо этого они становятся больше и размножаются. Чтобы предотвратить возникновение проблемы и дальнейшее нанесение ударов по дороге, вы либо: 1) устраняете ее и впоследствии убираете беспорядок, либо 2) сдерживаете ее, а затем убираете беспорядок.
Простое игнорирование исключений и ошибок и оставление их такими - это хороший способ испытать утечки памяти, выдающиеся соединения с базой данных, ненужные блокировки прав доступа к файлам и т. Д.
В редких случаях проблема настолько незначительна, тривиальна и - помимо необходимости в блоке try ... catch - самодостаточна , что на самом деле после этого просто нет беспорядка, который нужно убрать. Это единственный случай, когда эта лучшая практика не обязательно применяется. По моему опыту, это, как правило, означало, что то, что делает код, в основном мелкое и податливое, и что-то вроде попыток повторения или специальных сообщений не стоит ни сложности, ни удержания потока.
В моей компании правило состоит в том, чтобы почти всегда что- то делать в блоке перехвата, и если вы ничего не делаете, вы всегда должны размещать комментарий с очень веской причиной, почему бы и нет. Вы никогда не должны пропускать или оставлять пустой блок catch, когда есть что сделать.
источник
На мой взгляд, у ошибок есть причина, по которой я звучу глупо, но так оно и есть. Хорошее программирование вызывает ошибки только тогда, когда вам приходится с ними справляться. Кроме того, как я читал некоторое время назад, «pass-Statement - это оператор, который показывает, что код будет вставлен позже», поэтому, если вы хотите, чтобы пустой оператор извлечения был пустым, не стесняйтесь, но для хорошей программы найдется быть частью пропавшего. потому что вы не справляетесь с вещами, которые должны иметь. Появляющиеся исключения дают вам возможность исправить входные данные или изменить структуру данных, чтобы эти исключения не возникали снова (но в большинстве случаев (исключения сети (Общие исключения ввода)) указывают, что следующие части программы не будут работать должным образом. Например, исключение NetworkException может указывать на разорванное сетевое соединение, и программа не может отправлять / получать данные на следующих этапах программы.
Но использование проходного блока только для одного execption-блока допустимо, потому что вы все еще различаете типы исключений, поэтому, если вы поместите все блоки-исключения в один, он не будет пустым:
можно переписать так:
Таким образом, даже несколько блоков-исключений с операторами-pass могут привести к коду, структура которого обрабатывает особые типы исключений.
источник
Все приведенные комментарии действительны. По возможности вам нужно указать, какое именно исключение вы хотите игнорировать. Там, где это возможно, нужно анализировать причину исключения и игнорировать только то, что вы хотели игнорировать, а не все остальное. Если исключение приводит к «эффектному падению» приложения, то так и будет, потому что гораздо важнее знать, что произошло неожиданно, когда это произошло, чем скрывать, что проблема когда-либо возникала.
Несмотря на все сказанное, не принимайте никакую практику программирования в качестве первостепенной важности. Это глупо Всегда есть время и место для блока игнорировать все исключения.
Другим примером идиотской первостепенной важности является использование
goto
оператора. Когда я учился в школе, наш профессор научил нас,goto
оператора, просто упомянуть, что ты не будешь использовать его, НИКОГДА. Не верьте людям, говорящим вам, что xyz никогда не следует использовать, и не может быть сценария, когда он полезен. Там всегда есть.источник
Обработка ошибок очень важна в программировании. Вам нужно показать пользователю, что пошло не так. В очень немногих случаях вы можете игнорировать ошибки. Это очень плохая практика программирования.
источник
Поскольку это еще не было упомянуто, лучше использовать стиль
contextlib.suppress
:Обратите внимание, что в представленном примере состояние программы остается неизменным, независимо от того, происходит ли исключение. То есть
somefile.tmp
всегда становится несуществующим.источник