Про ловлю будь-якого винятку


697

Як я можу написати try/ exceptблок, який охоплює всі винятки?


4
У більшості випадків ви, мабуть, робите щось не так, якщо намагаєтесь знайти якийсь виняток. Я маю на увазі, що ви можете просто неправильно вписати щось у своєму коді, і навіть про це не дізнаєтесь. Добре застосовувати конкретні винятки.
vwvolodya

12
Якщо бути точнішим, ловити всі можливі винятки - це лише проблема, якщо їх спіймають мовчки. Важко подумати, куди ще підходить цей підхід, окрім того, де друкуються sys.stderrі, можливо, реєструються вловлювані повідомлення про помилки . Це абсолютно справедливий і поширений виняток.
Євгеній Сергєєв

Ви пробували: try: whatever() except Exception as e: exp_capture() ?
Чарлі Паркер

Відповіді:


564

Ви можете, але ви, мабуть, не повинні:

try:
    do_something()
except:
    print "Caught it!"

Однак це також сприйме винятки на кшталт, KeyboardInterruptі ви цього зазвичай не хочете, чи не так? Якщо ви не повторно підняли виняток - див. Наступний приклад із документів :

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise


15
Ваше останнє твердження не відповідає дійсності, вам потрібно чітко сказати, except Exception:що голі, за винятком випадків, коли ви також знайдете їх BaseException.
Pykler

7
Ви дійсно повинні надрукувати на stderr.
nyuszika7h

41
Я дуже категорично не згоден з твердженням "не слід". Ви повинні робити це економно. Бувають випадки, коли ви маєте справу з сторонніми бібліотеками (іноді динамічно завантажуються !!), які звелися з розуму за винятками, а відстеження їх усіх може бути дуже болючим завданням, і якщо ви пропустите лише одну, у вас дуже величезна хвороблива помилка у вашій системі. Це, як було сказано, добре відшукати стільки, скільки ви можете, і обробляти їх належним чином, а потім створити резервну копію всіх для тих, хто вам не вистачає.
Блейз

26
Що я також вважаю дивним, це те, що в мові набору качки, де ви не оголошуєте змінні екземпляри, раптом дуже стурбовано не введення всіх ваших винятків. Хм!
Блейз

838

Крім except:простого пункту (який, як інші сказали, не слід використовувати), ви можете просто зловити Exception:

import traceback
import logging

try:
    whatever()
except Exception as e:
    logging.error(traceback.format_exc())
    # Logs the error appropriately. 

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

Перевага except Exceptionнад голою exceptполягає в тому, що є декілька винятків, які він звичайно не вловив, KeyboardInterruptі SystemExitякщо ви їх зловили і проковтнули, то хтось може ускладнити вихід зі свого сценарію.


У мене було те саме, що в голові, але їх недолік - припустимо, що це дві помилки, коли один раз потрапляє, і, якщо ви тільки друкуєте, ви вийдете з блоку спробу, і другої помилки ви ніколи не дізнаєтесь .. .

6
Для всіх, хто цікавиться, цілком всупереч моєму сподіванню, це все одно буде сприймати не виключення підкласингу таких речей, як ints, принаймні в python 2.x.
Джозеф Гарвін

5
@JosephGarvin, це неправильно, тобто це не сприймає "невиключення", які не підклас Exception. Зауважте, що неможливо підняти intвиняток як виняток, і спроба зробити це викликає TypeErrorвиняток, який би сприймав додане except Exceptionзастереження в такому випадку. З іншого боку, клас старого стилю може бути піднято і кваліфікується як "не-виключення» , яка не підклас Exception- це буде спійманий на голому exceptпункт , але НЕ з допомогою except Exceptionпункту.
Йоель

4
@JosephGarvin перевірити цей запис у щоденнику: chris-lamb.co.uk/posts/no-one-expects-string-literal-exception Я з цим на @Yoel, ваше тестування просто замаскувалоTypeError
Duncan

2
@CharlieParker нічого поганого в тому, щоб зловити їх, якщо це те, що ти хочеш, але в основному ти цього не робиш. Виклик sys.exit()зазвичай означає, що ви очікуєте, що додаток припиниться, але якщо ви перейдете на SystemExit, він не стане. Так само якщо ви натиснете control-C на запущеному скрипті (Ctrl-перерва на windows), ви очікуєте, що програма зупиниться, а не виявить помилку і продовжуватиметься. Але ви можете зловити будь-яке / і те, і інше, якщо ви хочете зробити очищення раніше, ніж вони існували.
Дункан

100

Це можна зробити, щоб обробити загальні винятки

try:
    a = 2/0
except Exception as e:
    print e.__doc__
    print e.message

8
Це може не сприймати всі винятки, оскільки базовим класом для всіх винятків є BaseException, і я зіткнувся з виробничим кодом, який не належить до сімейства класів винятків. Докладніше про це див. У docs.python.org/3/library/… .
DDay

4
Це сприймає не всі винятки.
Andy_A̷n̷d̷y̷

6
Технічно він повинен охоплювати всі винятки, що не мають системи. З посилань на документи @DDay: " виняток BaseException: базовий клас для всіх вбудованих винятків. Він не має на увазі безпосередньо успадковуватися визначеними користувачем класами (для цього використовуйте Exception)." Якщо ви не працюєте з кодом, який ігнорує це, або вам потрібно вловлювати винятки, що виходять із системи, вищезазначене має бути нормально.
Пітер Кассетта

@PeterCassetta, коли хочеться зловити систему, яка виходить з винятків? Здається, загальна нитка у питанні, що ми не хочемо їх наздоганяти, але я не розумію, чому. Чому б зазвичай не?
Чарлі Паркер

68

Щоб зловити всі можливі винятки, ловіть BaseException . Він знаходиться на вершині ієрархії винятків:

Python 3: https://docs.python.org/3.5/library/exceptions.html#exception-hierarchy

Python 2.7: https://docs.python.org/2.7/library/exceptions.html#exception-hierarchy

try:
    something()
except BaseException as error:
    print('An exception occurred: {}'.format(error))

Але, як згадували інші люди, вам це зазвичай не знадобиться, лише для конкретних випадків.


1
Чи бажає зберегти хід довготривалої роботи після натискання клавіші Ctrl-C?
BallpointBen

54

Дуже простий приклад, подібний до знайденого тут:

http://docs.python.org/tutorial/errors.html#defining-clean-up-action

Якщо ви намагаєтеся знайти ВСІ винятки, то введіть увесь свій код в оператор "спробувати:" замість "друку" Виконання дії, яка може кинути виняток "."

try:
    print "Performing an action which may throw an exception."
except Exception, error:
    print "An exception was thrown!"
    print str(error)
else:
    print "Everything looks great!"
finally:
    print "Finally is called directly after executing the try statement whether an exception is thrown or not."

У наведеному вище прикладі ви побачите вихід у такому порядку:

1) Виконання дії, яка може кинути виняток.

2) Нарешті, викликається безпосередньо після виконання операції спробу, викинуто виняток чи ні.

3) "Виняток було кинуто!" або "Все виглядає чудово!" залежно від того, викинуто виняток.

Сподіваюся, це допомагає!


26

Існує кілька способів зробити це, зокрема, з Python 3.0 і вище

Підхід 1

Це простий підхід, але не рекомендується, оскільки ви точно не знаєте, який рядок коду насправді кидає виняток:

def bad_method():
    try:
        sqrt = 0**-1
    except Exception as e:
        print(e)

bad_method()

Підхід 2

Такий підхід рекомендується, оскільки він містить більш детальну інформацію про кожен виняток. Це включає:

  • Номер рядка для вашого коду
  • Назва файлу
  • Фактична помилка більш докладно

Єдиний недолік - імпорт tracback.

import traceback

def bad_method():
    try:
        sqrt = 0**-1
    except Exception:
        print(traceback.print_exc())

bad_method()

21

Щойно я дізнався цей маленький трюк для тестування, якщо імена виключень у Python 2.7. Іноді я обробляю конкретні винятки в коді, тому мені знадобився тест, щоб побачити, чи є це ім'я в списку оброблюваних винятків.

try:
    raise IndexError #as test error
except Exception as e:
    excepName = type(e).__name__ # returns the name of the exception

2
try:
    whatever()
except:
    # this will catch any exception or error

Варто згадати, що це не належне кодування Python. Це призведе також до багатьох помилок, які ви можете не хотіти.


просто використовуйте, за винятком того, що не кешуйте всі винятки, як згадується в деяких інших відповідях. Ви повинні використовувати BaseException для цієї мети, але, як ви вже сказали, ніхто не повинен вловлювати всі такі винятки. Я думаю, що для початку це нормально, якщо мета - додати ще більш деталізованого, за винятком розвитку, але я не думаю, що це буде ...
Pyglouthon
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.