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


777

Если вы просто хотите попробовать, кроме как обработать исключение, как вы это делаете в Python?

Является ли следующий способ сделать это правильно?

try:
    shutil.rmtree(path)
except:
    pass

10
Странно, что никто не упомянул об этом до сих пор (я сделал в своем ответе), но для этой конкретной функции вы можете просто сделать shutil.rmtree(path, ignore_errors=True). Однако это не относится к большинству функций.
Аарон Холл

9
Важно читать, думая об игнорировании исключений: почему «кроме: пройти» плохая практика программирования?
совать

3
Представь, что ты делаешь это в реальной жизни. try: get_cash ('$ 1000') за исключением: pass # meh, вероятно, все будет хорошо
Grokodile

Реальная жизнь:try: rob() except: run()
PatrickT

Ответы:


1039
try:
    doSomething()
except: 
    pass

или

try:
    doSomething()
except Exception: 
    pass

Разница в том, что первый тоже будет ловить KeyboardInterrupt, SystemExitи тому подобные вещи, которые получены напрямую exceptions.BaseException, а не exceptions.Exception.

Подробности смотрите в документации:


4
Обратите внимание, что StopIteration и Warning оба наследуются от Exception. В зависимости от ваших потребностей вы можете вместо этого наследовать от StandardError.
Бен Бланк

1
Это правда, но если вы не будете осторожны, вы можете столкнуться с небольшими ошибками (особенно если вы делаете что-то кроме передачи StopIteration).
Джейсон Бейкер

17
-1, try: shuti.rmtree(...) except: passбудет грубо подавлять любые ошибки (даже если вы ошиблись в shutilрезультате а NameError) - по крайней мере, делатьexcept OSError:
dbr

44
В этом ответе, хотя и информативном, отсутствует важная информация - вы никогда не должны поймать исключение таким образом. Вместо этого вы всегда должны пытаться поймать только те исключения, которые вас волнуют, иначе у вас будут кошмары, когда выискиваете тривиальные ошибки, скрытые вашими общими «кроме». Смотрите ответ dbr для получения дополнительной информации. (Я знаю, что это был не оригинальный вопрос - но любой, кто ищет это, просто возьмет ваш фрагмент и использует его как есть)
johndodo

139

Как правило, рекомендуется отлавливать только те ошибки, которые вас интересуют. В случае 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лучше использовать catch, а не просто except:выражение. Опять же почему?

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

>>> try:
...     sys.exit(1)
... except:
...     pass
... 
>>>

Сравните это со следующим, который правильно выходит:

>>> try:
...     sys.exit(1)
... except Exception:
...     pass
... 
shell:~$ 

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

import errno

try:
    shutil.rmtree(path)
except OSError as e:
    if e.errno != errno.ENOENT:
        # ignore "No such file or directory", but re-raise other errors
        raise

1
shutil.rmtreeэто не лучший пример, потому что вы просто использовали бы ignore_errors=Trueдля этой функции ..
Вим

113

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

Это зависит от того, что вы подразумеваете под «обработкой».

Если вы хотите поймать его без каких-либо действий, код, который вы разместили, будет работать.

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

try:
    do_something()
except:
    handle_exception()
    raise  #re-raise the exact same exception that was thrown

88

Сначала я процитирую ответ Джека О'Коннора из этой темы . Ссылочная тема закрыта, поэтому я пишу здесь:

«В 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

55

Для полноты:

>>> 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 err:
...     print("Handling run-time error:", err)

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

>>> try:
...     raise NameError('HiThere')
... except NameError:
...     print('An exception flew by!')
...     raise

... примеры из учебника по питону .


43

Как правильно игнорировать исключения?

Есть несколько способов сделать это.

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

Специфично для примера:

Вместо

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 

11

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

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

import sys
try:
    doSomething()
except:
    print "Unexpected error:", sys.exc_info()[0]

10
try:
      doSomething()
except Exception: 
    pass
else:
      stuffDoneIf()
      TryClauseSucceeds()

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


1
Наконец хорошее объяснение elseв этом контексте. И добавить, что всегдаfinally будет работать после любого (или без исключения).
not2qubit

5

Мне нужно было игнорировать ошибки в нескольких командах и fuckit сделал свое дело

import fuckit

@fuckit
def helper():
    print('before')
    1/0
    print('after1')
    1/0
    print('after2')

helper()

+1, потому что вы определенно сделали мой день, потому что внутри этого исходного кода вы можете узнать некоторые чрезвычайно полезные вещи, такие как изменение живого стека
WBAR

3

В 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...

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.