Capture várias exceções em uma linha (exceto o bloco)

2759

Eu sei que posso fazer:

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

Eu também posso fazer isso:

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

Mas se eu quiser fazer a mesma coisa em duas exceções diferentes, o melhor que posso pensar agora é fazer o seguinte:

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

Existe alguma maneira de fazer algo assim (desde que a ação a ser executada nas duas exceções seja say please):

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

Agora isso realmente não funcionará, pois corresponde à sintaxe de:

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

Portanto, meu esforço para capturar as duas exceções distintas não ocorre exatamente.

Existe uma maneira de fazer isso?

inspectorG4dget
fonte
6
Observe que no Python 3, o último não é mais uma sintaxe válida.
Gerrit 17/04/19

Respostas:

3726

Da documentação do Python :

Uma cláusula de exceção pode nomear várias exceções como uma tupla entre parênteses, por exemplo

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    pass

Ou, apenas para Python 2:

except (IDontLikeYouException, YouAreBeingMeanException), e:
    pass

A separação da exceção da variável por vírgula ainda funcionará no Python 2.6 e 2.7, mas agora está obsoleta e não funciona no Python 3; agora você deveria estar usando as.

carne_mecânica
fonte
9
Eu tentei ... com um list, e resultou em um TypeError. Parece que os erros devem estar em um tuplepara começar a funcionar como esperado.
usar o seguinte
4
Por que você nunca usou uma lista quando vê claramente que está documentado que uma tupla é necessária neste caso?
Mechanical_meat
6
Não ficou claro se a "tupla entre parênteses" era meramente sintática ou se era necessária uma tupla de boa-fé. "Parênteses" é enganoso porque você pode criar uma tupla sem parênteses em outro lugar e usá-la na exceptlinha. Só é necessariamente entre parênteses se criado na exceptlinha.
usar o seguinte
5
@ Josephphani, e as expressões geradoras?
jammertheprogrammer
12
@ Josephphani Isso não é verdade. Em 2 + (x * 2), (x * 2)certamente não é uma tupla. Parênteses são uma construção de agrupamento geral. A característica definidora de uma tupla é que ela contém uma vírgula - consulte a documentação do Python : "Observe que na verdade é a vírgula que faz uma tupla, não os parênteses".
Soren Bjornstad 12/07/19
314

Como capturar várias exceções em uma linha (exceto o bloco)

Faça isso:

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

Os parênteses são necessários devido à sintaxe mais antiga que usou as vírgulas para atribuir o objeto de erro a um nome. A aspalavra-chave é usada para a atribuição. Você pode usar qualquer nome para o objeto de erro, eu prefiro errorpessoalmente.

Melhor prática

Para fazer isso de uma maneira atualmente compatível com o Python e com o encaminhamento, você precisa separar as Exceções por vírgulas e colocá-las entre parênteses para diferenciar da sintaxe anterior que atribuiu a instância de exceção a um nome de variável, seguindo o tipo de Exceção a ser capturado com um vírgula.

Aqui está um exemplo de uso simples:

import sys

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

Estou especificando apenas essas exceções para evitar ocultar erros, dos quais, se eu encontrar, espero que o rastreamento completo da pilha seja feito.

Isso está documentado aqui: https://docs.python.org/tutorial/errors.html

É possível atribuir a exceção a uma variável ( eé comum, mas você pode preferir uma variável mais detalhada se tiver um tratamento longo de exceções ou se o IDE destacar apenas seleções maiores que essa, como a minha.) A instância possui um atributo args. Aqui está um exemplo:

import sys

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

Observe que no Python 3, o errobjeto fica fora de escopo quando o exceptbloco é concluído.

Descontinuada

Você pode ver o código que atribui o erro com uma vírgula. Esse uso, o único formulário disponível no Python 2.5 e versões anteriores, foi descontinuado e, se você deseja que seu código seja compatível com o encaminhamento no Python 3, atualize a sintaxe para usar o novo formulário:

import sys

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

Se você vir a atribuição de nome de vírgula na sua base de código e estiver usando o Python 2.5 ou superior, mude para a nova maneira de fazer isso, para que seu código permaneça compatível quando você atualizar.

O suppressgerenciador de contexto

A resposta aceita é realmente 4 linhas de código, no mínimo:

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

A try, except, passas linhas podem ser tratados de uma única linha com o gerente contexto suprimir, disponível em Python 3.4 :

from contextlib import suppress

with suppress(IDontLikeYouException, YouAreBeingMeanException):
     do_something()

Então, quando quiser, passem determinadas exceções, use suppress.

Aaron Hall
fonte
2
Boa adição de suppress, muito mais legível do que apenas fazer passemexcept
Mache
50

Da documentação do Python -> 8.3 Manipulando exceções :

Uma tryinstrução pode ter mais de uma exceção, para especificar manipuladores para diferentes exceções. No máximo, um manipulador será executado. Manipuladores tratam apenas exceções que ocorrem na cláusula try correspondente, não em outros manipuladores da mesma instrução try. Uma cláusula de exceção pode nomear várias exceções como uma tupla entre parênteses, por exemplo:

except (RuntimeError, TypeError, NameError):
    pass

Observe que os parênteses em torno dessa tupla são obrigatórios, porque, exceto ValueError, e:a sintaxe usada para o que normalmente é escrito, como except ValueError as e:no Python moderno (descrito abaixo). A sintaxe antiga ainda é suportada para compatibilidade com versões anteriores. Isso significa que except RuntimeError, TypeErrornão é equivalente, except (RuntimeError, TypeError):mas ao except RuntimeError as TypeError:qual não é o que você deseja.

fedorqui 'Então pare de prejudicar'
fonte
35

Se você usa frequentemente um grande número de exceções, pode predefinir uma tupla, para não precisar digitá-las novamente muitas vezes.

#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

NOTAS:

  1. Se você também precisar capturar outras exceções que não sejam as da tupla predefinida, precisará definir outro bloco, exceto.

  2. Se você simplesmente não pode tolerar uma variável global, defina-a em main () e passe-a onde for necessário ...

barba branca
fonte
17

Uma das maneiras de fazer isso é ..

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. 

e outra maneira é criar o método que executa a tarefa executada pelo exceptbloco e chamá-lo através de todo o exceptbloco que você escreve.

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]

Eu sei que o segundo não é a melhor maneira de fazer isso, mas estou apenas mostrando várias maneiras de fazer isso.

M.Usman
fonte
Estou usando o segundo porque tenho duas exceções diferentes que precisam ser processadas de maneira diferente. Existe algo errado em fazer dessa maneira?
21919 majikman
@majikman O segundo método com várias cláusulas, cada qual chamando a mesma função, não é o melhor quando você tenta não se repetir e faz o mesmo por duas exceções. (Veja as outras respostas para a maneira correta de fazer isso). No entanto, ter várias exceptcláusulas é normal quando você deseja manipular as exceções de maneira diferente.
Eponymous