Curso de Python / Tratar exceções com try, except, else, finally e raise
O tratamento de exceções permite reagir a falhas esperadas ou informar o problema a quem chamou uma função. Mantenha o bloco try focado na operação que pode falhar e capture somente os erros para os quais existe uma ação definida; esconder qualquer exceção pode deixar o programa continuar num estado incorreto.
Entender os caminhos de try, except, else e finally
O bloco try contém a operação monitorada. Se uma exceção ocorrer ali, as instruções restantes desse bloco são puladas e o Python procura um except compatível. Quando encontra, executa o tratamento; se não encontra, a exceção continua para um contexto externo e pode encerrar o programa.
else executa o caminho de sucesso quando o try termina normalmente, sem exceção e sem sair por uma instrução como return. Separar esse trabalho evita que o mesmo except capture por engano erros produzidos por etapas posteriores. Uma exceção levantada dentro de else ou de um tratador não é capturada pelos outros tratadores da mesma instrução try.
finally serve para ações de encerramento no fluxo normal de execução Python, inclusive quando há uma exceção a propagar. Não é uma garantia contra encerramento forçado do processo ou falha do sistema. Evite retornar de dentro desse bloco: um return ali pode substituir um retorno anterior ou suprimir uma exceção pendente.
Use raise para indicar explicitamente uma regra violada. Um valor digitado incorretamente pode permitir nova tentativa; uma falha de armazenamento pode exigir parar e avisar outra camada. O tratamento deve refletir essa diferença, em vez de produzir a mesma resposta para qualquer falha.
Executar valores aceitos e rejeitados
Salve o programa completo em exceptions_demo.py, com codificação UTF-8, numa pasta de prática. Execute python exceptions_demo.py no terminal com o ambiente virtual selecionado, se houver. Em macOS ou Ubuntu sem ambiente virtual, use python3 exceptions_demo.py quando necessário. Não há dependências externas nem arquivos de dados para criar.
def parse_amount(text):
amount = int(text)
if amount < 0:
raise ValueError("amount must be nonnegative")
return amount
for text in ["8000", "abc", "-1"]:
try:
amount = parse_amount(text)
except ValueError as error:
print("invalid:", text)
else:
print("accepted:", amount)
finally:
print("checked")
A saída esperada é:
accepted: 8000
checked
invalid: abc
checked
invalid: -1
checked
parse_amount() primeiro tenta converter o texto com int(). Para "8000", a conversão e a regra de valor não negativo passam; o retorno chega ao chamador e o bloco else imprime accepted: 8000, isto é, “aceito: 8000”. O texto "abc" falha na conversão. Já "-1" vira um inteiro, mas a função levanta seu próprio ValueError por violar a regra.
Os dois últimos casos seguem o mesmo tratador e exibem invalid, “inválido”, com a entrada. Em todos os três caminhos, finally imprime checked, “verificado”. Essa mensagem mostra que a tentativa terminou; ela não significa que o valor foi aceito. O laço continua após os erros tratados e testa o próximo texto.
Escolher o que recuperar e o que propagar
O exemplo captura ValueError porque há uma política clara: rejeitar esse texto e continuar. Se uma entrada como None for passada, int(None) gera TypeError, que esse tratador não captura. Ainda assim, finally executa antes de o erro continuar para fora. A função pressupõe texto como entrada; mudar o contrato exige decidir como tratar tipos diferentes.
Uma cláusula ampla como except Exception: pass elimina informações e pode ocultar defeitos que não eram erros recuperáveis de entrada. Quando a camada atual só consegue registrar contexto, um raise isolado dentro do except propaga a exceção original. Capturar e retornar um valor, por outro lado, faz o chamador receber esse valor e continuar normalmente; use isso apenas quando ele representa uma recuperação definida.
Quando outra camada precisa de uma exceção mais adequada ao seu contrato, raise NovoErro(...) from error permite associar a nova exceção à causa original. Isso preserva o encadeamento para diagnóstico. A documentação de erros, tratadores e encadeamento de exceções apresenta essas alternativas.
Para arquivos e outros recursos, prefira um gerenciador de contexto apropriado, como na prática de arquivos abertos com with. Uma limpeza manual em finally precisa considerar que a criação do recurso pode ter falhado: tentar fechar um objeto que nunca foi associado pode gerar outro erro e dificultar o diagnóstico do primeiro.
Comparar os casos e manter o diagnóstico útil
- Acrescente
"0"ao fim da lista do laço. A saída adicional deve seraccepted: 0seguida dechecked. Zero atende à regra de não negatividade. - Restaure a lista e acrescente uma string vazia,
"". A saída adicional deve serinvalid:, com o espaço usado peloprint, seguida dechecked. A falha ocorre na conversão para inteiro. - Para comparar as causas num teste local, acrescente temporariamente
print(type(error).__name__, str(error))dentro doexcept, depois da impressão existente. O casoabcinforma falha de conversão; o caso negativo mostraamount must be nonnegative, “o valor deve ser não negativo”. Ambos sãoValueError, mas surgem em etapas diferentes. A redação da mensagem interna de conversão pode variar entre versões. - Retire a impressão de diagnóstico e os valores adicionais. Execute novamente e confirme as seis linhas originais, com uma mensagem
checkedpara cada entrada.
Ao lidar com dados reais, mensagens de exceção podem incluir conteúdo recebido, caminhos ou informações privadas. O exemplo só usa textos de teste; não copie indiscriminadamente mensagens e entradas para uma tela pública ou para logs. Dê ao usuário uma indicação do que ele pode corrigir e registre apenas o contexto necessário para investigar o problema.
Teste a saída de sucesso, a recuperação esperada e a propagação dos erros não tratados separadamente. Uma mensagem de finalização sozinha não comprova que o trabalho principal terminou corretamente, e a ausência de uma exceção não comprova que ela foi resolvida. A referência da instrução try e suas cláusulas permite conferir a ordem e os limites de cada caminho.




