Как правильно игнорировать исключения
Если вы просто хотите попробовать, кроме как обработать исключение, как вы это делаете в Python?
Является ли следующий правильный способ сделать это?
try:
shutil.rmtree(path)
except:
pass
14 ответов
try:
doSomething()
except:
pass
или же
try:
doSomething()
except Exception:
pass
Разница в том, что первый тоже поймает KeyboardInterrupt
, SystemExit
и тому подобное, которые получены непосредственно из exceptions.BaseException
не exceptions.Exception
,
Подробности смотрите в документации:
- Попробуйте оператор - http://docs.python.org/reference/compound_stmts.html
- исключения - http://docs.python.org/library/exceptions
Обычно считается, что лучше всего ловить только те ошибки, которые вас интересуют. В случае shutil.rmtree
это, вероятно OSError
:
>>> shutil.rmtree("/fake/dir")
Traceback (most recent call last):
[...]
OSError: [Errno 2] No such file or directory: '/fake/dir'
Если вы хотите игнорировать эту ошибку, вы должны сделать:
try:
shutil.rmtree(path)
except OSError:
pass
Зачем? Скажем, вы (как-то) случайно передали функции целое число вместо строки, например:
shutil.rmtree(2)
Это выдаст ошибку "TypeError: приведение к Unicode: нужна строка или буфер, int найдена" - вы, вероятно, не хотите игнорировать это, что может быть трудно отладить.
Если вы определенно хотите игнорировать все ошибки, поймайте Exception
а не голый except:
заявление. Опять же почему?
Не указав исключение, ловит каждое исключение, включая SystemExit
исключение, которое, например, sys.exit()
использует:
>>> try:
... sys.exit(1)
... except:
... pass
...
>>>
Сравните это со следующим, который правильно выходит:
>>> try:
... sys.exit(1)
... except Exception:
... pass
...
shell:~$
Если вы хотите написать более качественный код, OSError
исключение может представлять различные ошибки, но в приведенном выше примере мы хотим только игнорировать Errno 2
так что мы могли бы быть еще более конкретными:
try:
shutil.rmtree(path)
except OSError, e:
if e.errno == 2:
# suppress "No such file or directory" error
pass
else:
# reraise the exception, as it's an unexpected error
raise
Вы могли бы также import errno
и изменить if
в if e.errno == errno.ENOENT:
Сначала я процитирую ответ Джека О'Коннора из этой темы. Ссылочная тема закрыта, поэтому я пишу здесь:
"В Python 3.4 появился новый способ сделать это:
from contextlib import suppress
with suppress(Exception):
# your code
Вот коммит, который его добавил: http://hg.python.org/cpython/rev/406b47c64480
И вот автор, Рэймонд Хеттингер, говорит об этом и о всякой другой горячности Python: https://youtu.be/OSGv2VnC0go?t=43m23s
Мое дополнение к этому является эквивалентом Python 2.7:
from contextlib import contextmanager
@contextmanager
def ignored(*exceptions):
try:
yield
except exceptions:
pass
Затем вы используете его, как в Python 3.4:
with ignored(Exception):
# your code
Если вы просто хотите сделать попытку catch без обработки исключения, как вы это делаете в Python?
Это зависит от того, что вы подразумеваете под "обработкой".
Если вы хотите поймать его без каких-либо действий, отправленный вами код будет работать.
Если вы имеете в виду, что хотите выполнить действие для исключения, не останавливая исключение при переходе вверх по стеку, то вам нужно что-то вроде этого:
try:
do_something()
except:
handle_exception()
raise #re-raise the exact same exception that was thrown
Для полноты:
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print "division by zero!"
... else:
... print "result is", result
... finally:
... print "executing finally clause"
... из учебника по питону.
Также обратите внимание, что вы можете захватить исключение следующим образом:
>>> try:
... this_fails()
... except ZeroDivisionError as detail:
... print 'Handling run-time error:', detail
Как правильно игнорировать исключения?
Есть несколько способов сделать это.
Однако выбор примера имеет простое решение, которое не распространяется на общий случай.
Специфично для примера:
Вместо
try:
shutil.rmtree(path)
except:
pass
Сделай это:
shutil.rmtree(path, ignore_errors=True)
Это аргумент, специфичный для shutil.rmtree
, Вы можете увидеть справку по ней, выполнив следующее, и вы также увидите, что она также может учитывать и ошибки.
>>> import shutil
>>> help(shutil.rmtree)
Так как это охватывает только узкий случай примера, я далее продемонстрирую, как справиться с этим, если эти ключевые аргументы не существуют.
Общий подход
Поскольку вышеизложенное охватывает только узкий случай примера, я дополнительно продемонстрирую, как справиться с этим, если эти ключевые аргументы не существуют.
Новое в Python 3.4:
Вы можете импортировать suppress
менеджер контекста:
from contextlib import suppress
Но подавим только самое конкретное исключение:
with suppress(FileNotFoundError):
shutil.rmtree(path)
Вы будете молча игнорировать FileNotFoundError
:
>>> with suppress(FileNotFoundError):
... shutil.rmtree('bajkjbkdlsjfljsf')
...
>>>
Из документов:
Как и с любым другим механизмом, который полностью подавляет исключения, этот диспетчер контекста должен использоваться только для покрытия очень специфических ошибок, когда известно, что правильное выполнение - это молчаливое продолжение выполнения программы.
Обратите внимание, что suppress
а также FileNotFoundError
доступны только в Python 3.
Если вы хотите, чтобы ваш код работал и в Python 2, см. Следующий раздел:
Python 2 и 3:
Если вы просто хотите сделать попытку / исключение без обработки исключения, как вы это сделаете в Python?
Является ли следующий правильный способ сделать это?
try : shutil.rmtree ( path ) except : pass
Для Python 2-совместимого кода, pass
это правильный способ получить утверждение, которое не является опцией. Но когда вы делаете голый except:
это то же самое, что делать except BaseException:
который включает в себя GeneratorExit
, KeyboardInterrupt
, а также SystemExit
и вообще, ты не хочешь ловить эти вещи.
На самом деле, вы должны быть как можно точнее в названии исключения.
Вот часть иерархии исключений Python (2), и, как вы можете видеть, если вы поймете более общие исключения, вы можете скрыть проблемы, которые вы не ожидали:
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StandardError
| +-- BufferError
| +-- ArithmeticError
| | +-- FloatingPointError
| | +-- OverflowError
| | +-- ZeroDivisionError
| +-- AssertionError
| +-- AttributeError
| +-- EnvironmentError
| | +-- IOError
| | +-- OSError
| | +-- WindowsError (Windows)
| | +-- VMSError (VMS)
| +-- EOFError
... and so on
Вы, вероятно, хотите поймать здесь OSError, и, возможно, исключение, которое вас не волнует, это отсутствие каталога.
Мы можем получить этот конкретный номер ошибки из errno
библиотека, и ререйз, если у нас его нет:
import errno
try:
shutil.rmtree(path)
except OSError as error:
if error.errno == errno.ENOENT: # no such file or directory
pass
else: # we had an OSError we didn't expect, so reraise it
raise
Обратите внимание, что голый рейз поднимает исходное исключение, что, вероятно, то, что вы хотите в этом случае. Написано более кратко, поскольку нам не нужно явно pass
с кодом в обработке исключений:
try:
shutil.rmtree(path)
except OSError as error:
if error.errno != errno.ENOENT: # no such file or directory
raise
@ Когда вы просто хотите попробовать поймать без обработки исключения, как вы это делаете в Python?
Это поможет вам напечатать, что такое исключение:(то есть попробуйте перехватить без обработки исключения и распечатать исключение.)
импорт системы.... пытаться: сделай что-нибудь() Кроме: выведите "неожиданная ошибка:", sys.exc_info()[0] ...
рег, Тилокчан
try:
doSomething()
except Exception:
pass
else:
stuffDoneIf()
TryClauseSucceeds()
Кстати, предложение else может идти после всех исключений и будет выполняться только в том случае, если код в попытке не вызывает исключение.
В Python мы обрабатываем исключения, похожие на другие языки, но разница в некоторой разнице в синтаксисе, например,
try:
#Your code in which exception can occur
except <here we can put in a particular exception name>:
# We can call that exception here also, like ZeroDivisionError()
# now your code
# We can put in a finally block also
finally:
# Your code...
Что ж, это не попытка, а еще один способ обработки исключений, если вам нравится объектно-ориентированное программирование:
class MyExceptionHandler:
def __enter__(self):
... # Do whatever when "with" block is started
return self
def __exit__(self, exc_type, exc_value, tb):
return True
А затем к собственному коду:
with MyExceptionHandler():
... # Code that may or may not raise an exception
shutil.rmtree(path)
Как это работает?
-
__enter__
запускается при входе в блок. -
__exit__
запускается при выходе изwith
блокировать- Это должно вернуться
True
чтобы заглушить возможное исключение. - Это должно вернуться
None
(или что-то, что считается ложным), чтобы не заглушить потенциальное исключение. - Тип исключения, фактическое исключение и его трассировка передаются как (позиционные) аргументы. Вы можете использовать их, чтобы определить, что делать.
- Это должно вернуться
В заключение, предпочтение отдается try-except. Это может быть полезно, если вам нужно больше абстракции, чем обычно.
Обработка исключения в Python: если у вас есть подозрительный код, который может вызвать исключение, вы можете защитить свою программу, поместив подозрительный код в блок try:.
try:
# Your statements .............
except ExceptionI:
# Your statements.............
except ExceptionII:
# Your statements..............
else:
# Your statements
Просто вызовите соответствующее исключение, вот так:
try:
raise NameError('Joan')
except NameError:
print 'An exception just raised again by Joan!'
raise
Так просто.:)
Для получения более подробной информации, прочитайте эту документацию: https://docs.python.org/3.6/tutorial/errors.html