Como não lidar com exceções em Python

Eu vejo muitas pessoas lidando com exceções da maneira errada. Talvez isso se aplique a você também. A situação a seguir soa familiar?
Você está escrevendo algum código, mas sabe que a biblioteca que está usando pode gerar uma exceção. Você não se lembra qual, exatamente. Neste ponto, é tentador usar os chamados blocos catch-all e continuar com as coisas divertidas.
Índice
A pior maneira de fazer isso
O pior que você pode fazer é criar um bloco try-except que capture qualquer coisa. Por catch-all, quero dizer algo como:
try: ... except: pass
Blocos catch-all como esses são ruins porque:
- Você não tem ideia de quais outras exceções podem ser levantadas (mais sobre isso mais tarde).
- Estamos ocultando a exceção usando a passagem silenciosamente em vez de registrar o erro.
Além disso, um except vazio pegará tudo, incluindo
KeyboardInterrupt
(controle + c), SystemExit
, e até NameErrors
! Isso significa que o código a seguir não pode ser interrompido de forma limpa:from time import sleep while True: try: print("Try and stop me") sleep(1) except: print("Don't.. stop.. me now!")
Sinta-se à vontade para experimentá-lo. Você precisa fechar a janela do terminal ou matar o processo Python para parar este programa.
Uma maneira um pouco melhor de capturar todas as exceções
Por outro lado, ao usar
except Exception
, embora ainda seja uma maneira rápida e suja de capturar muitas exceções, pelo menos você poderá interromper o processo em execução corretamente:from time import sleep while True: try: print("Try and stop me") sleep(1) except Exception: print("Ok I'll stop!")
Ao capturar
Exception
você não pegará SystemExit
, KeyboardInterrupt
e outras exceções semelhantes. Por que isso, você pergunta? Todas as exceções herdam de uma classe chamada
BaseException
. De acordo com a documentação oficial:“Em um try
instrução com um except
cláusula que menciona uma classe específica, essa cláusula também trata de quaisquer classes de exceção derivadas dessa classe.” Um except
vazio é equivalente a except BaseException
, portanto, ele capturará todas as exceções possíveis. Por outro lado, a classe
Exception
é definido como:“Todas as exceções internas que não saem do sistema são derivadas desta classe. Todas as exceções definidas pelo usuário também devem ser derivadas desta classe.” Fica ainda pior
No exemplo a seguir, usamos a biblioteca os para obter o diretório de trabalho atual. No entanto, meus dedinhos gordos cometeram um erro de digitação:
import os try: working_dir = os.getcdw() print(working_dir) except: print('error')
Porque
os.getcdw
não é uma função no módulo os, um NameError é lançado. Em vez de falhar, a cláusula except detectará o erro, imprimirá 'erro' e o programa continuará apesar de nosso erro de digitação flagrante. Infelizmente, este não pode ser resolvido capturando Exception
qualquer! Aparentemente, nosso pequeno truque do primeiro passo não é uma solução para todos os nossos problemas. Então, o que deve nós fazemos?
Pegue o que você pode manipular
Uma frase que muitas vezes é ouvida sobre exceções é:pegue o que você pode manipular . Muitos desenvolvedores são tentados a lidar diretamente com exceções, embora muitas vezes seja melhor deixar a exceção se propagar para uma parte do seu programa que possa realmente lidar com ela.
Por exemplo, considere a parte de um editor de texto que abre e carrega arquivos, vamos chamá-la de
OpenFile
classe. Se o usuário solicitou a abertura de um arquivo que não existe, você pode manipular diretamente esse erro ou deixá-lo se propagar. Nesse caso, é melhor propagar a exceção para o chamador, porque
OpenFile
não tem ideia de quão ruim é essa exceção para o chamador. O chamador pode lidar com a situação de várias maneiras:- Pode criar um novo arquivo com esse nome e continuar
- Talvez o chamador precise que o arquivo esteja lá, nesse caso ele pode mostrar uma caixa de diálogo de erro para informar ao usuário que esse arquivo não existe.
De qualquer forma, não depende do
OpenFile
class para decidir o que fazer no caso de um FileNotFoundError
. Então, uma exceção deve sempre ser propagada? Não. Uma possível exceção que pode ser tratada na classe FileOpen é a
TimeoutError
. Você pode tentar novamente algumas vezes, por exemplo, sem incomodar o chamador com o erro. Esta é uma exceção que OpenFile
pode lidar, então não há problema em pegá-lo e tentar novamente. Conclusão
Você não deve, sob nenhuma circunstância, capturar mais exceções do que pode manipular. Blanket exceto blocos são uma receita para bugs e código imprevisível. Em outras palavras:pegue o que você pode manipular.
Se você escrever seu código com a matra 'pegue o que você pode manipular' em mente, escrever blocos pega-tudo está quebrando todas as regras. Então, por favor, pare de fazer isso. Como exercício, você pode revisitar alguns de seus códigos existentes e ver se eles podem ser melhorados com esse novo conhecimento!
python
- Operadores Python
- Erros do Python e exceções incorporadas
- Exceções personalizadas do Python
- Como obter data e hora atuais em Python?
- Java captura múltiplas exceções
- Como não ser péssimo em ensinar um novo software
- Instrução Python Print():Como imprimir com exemplos
- Python Dictionary Append:Como adicionar um par de chave/valor
- Python New Line:Como imprimir SEM Newline em Python
- Python Average:Como encontrar a AVERAGE de uma lista em Python