Поймать несколько исключений в одной строке (кроме блока)


2760

Я знаю, что я могу сделать:

try:
    # do something that may fail
except:
    # do this if ANYTHING goes wrong

Я также могу сделать это:

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreTooShortException:
    # stand on a ladder

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

try:
    # do something that may fail
except IDontLikeYouException:
    # say please
except YouAreBeingMeanException:
    # say please

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

try:
    # do something that may fail
except IDontLikeYouException, YouAreBeingMeanException:
    # say please

Теперь это действительно не будет работать, так как он соответствует синтаксису для:

try:
    # do something that may fail
except Exception, e:
    # say please

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

Есть ли способ сделать это?


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

Ответы:


3728

Из документации Python :

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

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

Или только для Python 2:

except (IDontLikeYouException, YouAreBeingMeanException), e:
    pass

Отделение исключения от переменной запятой будет по-прежнему работать в Python 2.6 и 2.7, но теперь устарело и не работает в Python 3; Теперь вы должны использовать as.


9
Я попробовал это ... с list, и это привело к TypeError. Похоже, что ошибки должны быть в tupleловле, чтобы работать, как ожидалось.
BallpointBen

4
Зачем вам когда-либо использовать список, если вы четко видите, что в документации задано, что в этом случае необходим кортеж?
mechanical_meat

6
Было неясно, был ли «заключенный в скобки кортеж» просто синтаксическим или требовался добросовестный кортеж. «Скобки» вводят в заблуждение, потому что вы можете создать кортеж без скобок в другом месте, а затем использовать его в exceptстроке. Он обязательно должен быть заключен в скобки, если он создан в exceptстроке.
BallpointBen

5
@JosephBani, как насчет выражений генератора?
jammertheprogrammer

12
@JosephBani Это совсем не так. В 2 + (x * 2), (x * 2)конечно, не кортеж. Скобки - это общая группирующая конструкция. Определяющей характеристикой кортежа является то, что он содержит запятую - см. Документацию Python : «Обратите внимание, что на самом деле кортеж - это запятая , а не скобки».
Сорен Бьорнстад

314

Как перехватить несколько исключений в одной строке (кроме блока)

Сделай это:

try:
    may_raise_specific_errors():
except (SpecificErrorOne, SpecificErrorTwo) as error:
    handle(error) # might log or have some other default behavior...

Скобки требуются из-за более старого синтаксиса, который использовал запятые, чтобы назначить объект ошибки имени. asКлючевое слово используется для задания. Вы можете использовать любое имя для объекта ошибки, я предпочитаю errorлично.

Лучшая практика

Чтобы сделать это способом, совместимым в настоящее время и в будущем с Python, вам необходимо отделить Исключения запятыми и заключить их в скобки, чтобы отличать их от более раннего синтаксиса, который назначал экземпляр исключения имени переменной, следуя типу Исключения, который должен быть пойман с помощью запятая.

Вот пример простого использования:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError): # the parens are necessary
    sys.exit(0)

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

Это задокументировано здесь: https://docs.python.org/tutorial/errors.html

Вы можете назначить исключение переменной ( eобычно, но вы можете предпочесть более подробную переменную, если у вас длинная обработка исключений или ваша IDE выделяет только те выделения, которые больше, чем у меня.) Экземпляр имеет атрибут args. Вот пример:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError) as err: 
    print(err)
    print(err.args)
    sys.exit(0)

Обратите внимание, что в Python 3 errобъект выпадает из области видимости после завершения exceptблока.

Устаревшее

Вы можете увидеть код, который присваивает ошибку с запятой. Это использование, единственная форма, доступная в Python 2.5 и более ранних версиях, устарело, и если вы хотите, чтобы ваш код был напрямую совместим с Python 3, вы должны обновить синтаксис для использования новой формы:

import sys

try:
    mainstuff()
except (KeyboardInterrupt, EOFError), err: # don't do this in Python 2.6+
    print err
    print err.args
    sys.exit(0)

Если вы видите назначение запятой в своей кодовой базе и используете Python 2.5 или выше, переключитесь на новый способ, чтобы ваш код оставался совместимым при обновлении.

suppressМенеджер контекста

Принятый ответ - минимум 4 строки кода:

try:
    do_something()
except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

try, except, passЛинии могут быть обработаны в одной строке с менеджером контекста подавить, доступную в Python 3.4 :

from contextlib import suppress

with suppress(IDontLikeYouException, YouAreBeingMeanException):
     do_something()

Поэтому, когда вы хотите использовать passопределенные исключения, используйте suppress.


2
Хорошее дополнение suppress, много более читаемым , чем просто делать passнаexcept
Маше

50

Из документации Python -> 8.3 Обработка исключений :

tryЗаявление может иметь более одного , за исключением пункта, чтобы указать обработчик для разных исключений. Максимум один обработчик будет выполнен. Обработчики обрабатывают только исключения, возникающие в соответствующем предложении try, но не в других обработчиках того же оператора try. Предложение исключением может называть несколько исключений в виде кортежа в скобках, например:

except (RuntimeError, TypeError, NameError):
    pass

Обратите внимание, что круглые скобки вокруг этого кортежа обязательны, потому что за исключением того, ValueError, e:что использовался синтаксис для того, что обычно пишется как except ValueError as e:в современном Python (описано ниже). Старый синтаксис все еще поддерживается для обратной совместимости. Это означает, except RuntimeError, TypeErrorчто не эквивалентно, except (RuntimeError, TypeError):но то, except RuntimeError as TypeError:что не то, что вы хотите.


35

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

#This example code is a technique I use in a library that connects with websites to gather data

ConnectErrs  = (URLError, SSLError, SocketTimeoutError, BadStatusLine, ConnectionResetError)

def connect(url, data):
    #do connection and return some data
    return(received_data)

def some_function(var_a, var_b, ...):
    try: o = connect(url, data)
    except ConnectErrs as e:
        #do the recovery stuff
    blah #do normal stuff you would do if no exception occurred

НОТЫ:

  1. Если вам также необходимо перехватить другие исключения, кроме тех, которые находятся в предопределенном кортеже, вам нужно определить другое, кроме блока.

  2. Если вы просто не можете терпеть глобальную переменную, определите ее в main () и передайте, где это необходимо ...


17

Один из способов сделать это ..

try:
   You do your operations here;
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   If there is any exception from the given exception list, 
   then execute this block.
   ......................
else:
   If there is no exception then execute this block. 

а другой способ - создать метод, который выполняет задачу, выполняемую exceptблоком, и вызвать ее через весь exceptблок, который вы пишете.

try:
   You do your operations here;
   ......................
except Exception1:
    functionname(parameterList)
except Exception2:
    functionname(parameterList)
except Exception3:
    functionname(parameterList)
else:
   If there is no exception then execute this block. 

def functionname( parameters ):
   //your task..
   return [expression]

Я знаю, что второй не лучший способ сделать это, но я просто показываю несколько способов сделать это.


Я использую второе, потому что у меня есть два разных исключения, каждое из которых должно обрабатываться по-разному. Что-то не так с этим?
Мажикман

@majikman Второй метод с несколькими предложениями, каждый из которых вызывает одну и ту же функцию, не самый лучший, когда вы пытаетесь не повторяться и делаете одно и то же для двух исключений. (Смотрите другие ответы для правильного способа сделать это). Однако наличие нескольких exceptпредложений - это нормально, если вы хотите обрабатывать исключения по-разному.
Одноименный
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.