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

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

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

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

inspectorG4dget
источник
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.

mechanical_meat
источник
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]

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

M.Usman
источник
Я использую второе, потому что у меня есть два разных исключения, каждое из которых должно обрабатываться по-разному. Что-то не так с этим?
Мажикман
@majikman Второй метод с несколькими предложениями, каждый из которых вызывает одну и ту же функцию, не самый лучший, когда вы пытаетесь не повторяться и делаете одно и то же для двух исключений. (Смотрите другие ответы для правильного способа сделать это). Однако наличие нескольких exceptпредложений - это нормально, если вы хотите обрабатывать исключения по-разному.
Одноименный