Як правильно ігнорувати винятки


776

Коли ви просто хочете зробити спробу, за винятком випадків, не обробляючи виняток, як це зробити в Python?

Чи є наступним правильним способом це зробити?

try:
    shutil.rmtree(path)
except:
    pass

10
Дивно, що досі про це ніхто не згадував (я це робив у своїй відповіді), але для цієї конкретної функції можна просто зайнятися shutil.rmtree(path, ignore_errors=True). Однак це не стосується більшості функцій.
Аарон Холл

9
Важливо читати, думаючи про ігнорування винятків: Чому "крім: пройти" є поганою практикою програмування?
ткнути

3
Уявіть, що це робите в реальному житті. спробуйте: get_cash ('$ 1000') за винятком: пройдіть # мех, це, мабуть, буде добре
Грокоділе,

Відповіді:


1039
try:
    doSomething()
except: 
    pass

або

try:
    doSomething()
except Exception: 
    pass

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

Детальну інформацію див. У документації:


4
Зауважте, що StopIteration та попередження успадковуються і від винятку. Залежно від ваших потреб, ви можете замість цього перейти у спадок від StandardError.
Бен Бланк

1
Це правда, але якщо ви не обережні, ви можете зіткнутися з тонкими помилками (особливо, якщо ви робите щось інше, ніж передавати StopIteration).
Джейсон Бейкер

17
-1, try: shuti.rmtree(...) except: passбуде жорстоко придушити будь-які помилки (навіть якщо ви неправильно shutilNameErrorexcept OSError:
написали,

44
Ця відповідь, хоч і є інформативною, не містить важливої ​​інформації - таким чином ніколи не слід виловлювати виняток. Натомість завжди слід намагатися спіймати лише ті винятки, які вас хвилюють, інакше у вас з’являться кошмари, коли ви полюєте на тривіальних помилок, прихованих вашими родовими «за винятком» s. Див. Відповідь 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а не голий 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

Спочатку я цитую відповідь Джека o'Connor з цієї теми . Посилальна нитка закрилася, і я пишу тут:

"У 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?

Це допоможе вам роздрукувати, що таке виняток :( тобто спробуйте catch, не обробляючи виняток, і надрукуйте виняток.)

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

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

FYI, інше застереження може виконуватись після всіх винятків і запускатиметься лише в тому випадку, якщо код у спробі не викликає винятку.


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.