Tratamento de Exceções em Python

PythonBeginner
Pratique Agora

Introdução

Na computação e na programação, o tratamento de exceções é o processo de responder à ocorrência de exceções – condições anômalas ou excepcionais que exigem um processamento especial. O Python possui muitas exceções integradas que são disparadas quando um programa encontra um erro. Além disso, muitas bibliotecas externas incluem suas próprias exceções personalizadas que você precisará tratar.

Neste laboratório, você aprenderá os fundamentos do tratamento de exceções em Python. Você começará com blocos básicos de try e except, avançará para o tratamento de múltiplas exceções, entenderá o uso do bloco finally e, por fim, criará e gerenciará suas próprias exceções personalizadas.

Tratamento Básico de Exceções

Nesta etapa, você aprenderá os fundamentos do tratamento de exceções em Python usando os blocos try e except.

É um fato matemático que não se pode dividir por zero. Se você tentar fazer isso em Python, o interpretador disparará uma ZeroDivisionError integrada. Vamos ver isso na prática.

Nota: Se você não estiver familiarizado com o uso do WebIDE (semelhante ao VS Code), aprenda primeiro neste laboratório.

Primeiro, abra o arquivo basic_handler.py no explorador de arquivos à esquerda e adicione o seguinte código. Isso define uma função de divisão simples.

def divide(dividend , divisor):
    print(dividend / divisor)

divide(dividend=10, divisor=5)

Agora, execute o script no terminal:

python3 basic_handler.py

Você verá a saída correta:

2.0

Em seguida, vamos ver o que acontece quando tentamos dividir por zero. Modifique a última linha em basic_handler.py para chamar divide com um divisor igual a 0:

def divide(dividend , divisor):
    print(dividend / divisor)

divide(dividend=10, divisor=0)

Execute o script novamente:

python3 basic_handler.py

Desta vez, o programa trava e exibe um traceback, indicando um ZeroDivisionError:

Traceback (most recent call last):
  File "/home/labex/project/basic_handler.py", line 4, in <module>
    divide(dividend=10, divisor=0)
  File "/home/labex/project/basic_handler.py", line 2, in divide
    print(dividend / divisor)
ZeroDivisionError: division by zero

Para evitar que o programa trave e, em vez disso, exibir uma mensagem amigável ao usuário, podemos "tratar" a exceção usando try e except. O código que pode causar um erro é colocado dentro do bloco try, e o código a ser executado se esse erro ocorrer é colocado no bloco except.

Atualize o arquivo basic_handler.py com o seguinte código para tratar a ZeroDivisionError de forma elegante:

## try-except: tratar exceções de forma elegante
def divide(dividend , divisor):
    try:  ## Tente executar este código
        print(dividend / divisor)
    except ZeroDivisionError:  ## Capture um tipo de exceção específico
        print('You can not divide by 0')

divide(dividend=10, divisor=0)

Agora, execute o script mais uma vez:

python3 basic_handler.py

Em vez de travar, o programa agora imprime a mensagem útil que você definiu, e a execução termina normalmente:

You can not divide by 0

Tratando Múltiplas Exceções Usando um Único Bloco

Nesta etapa, você descobrirá como tratar vários tipos diferentes de exceções dentro de um único bloco except. Isso é útil para simplificar seu código de tratamento de erros quando vários tipos de erros podem ocorrer.

Você pode capturar uma tupla de exceções, como (ZeroDivisionError, TypeError), para tratá-las com a mesma lógica.

Abra o arquivo multiple_handler.py e adicione o seguinte código. Esta função foi projetada para potencialmente disparar uma TypeError (ao tentar concatenar uma string e um inteiro) ou uma ZeroDivisionError.

## Tratar múltiplas exceções em um único bloco except
def divide(dividend , divisor):
    try:
        if (dividend == 10):
          var = 'str' + 1  ## Isso disparará TypeError
        else:
          print(dividend / divisor)
    except (ZeroDivisionError, TypeError) as error:  ## Capturar múltiplos tipos de exceção
        print(error)  ## Imprimir a mensagem de erro

divide(dividend=20, divisor=5)

Primeiro, vamos executar o código em um cenário onde nenhuma exceção ocorre. Execute o script:

python3 multiple_handler.py

A saída será o resultado da divisão:

4.0

Agora, vamos disparar a TypeError. Modifique a última linha de multiple_handler.py para usar 10 como dividendo:

## ... (rest of the code) ...
divide(dividend=10, divisor=5)

Execute o script novamente:

python3 multiple_handler.py

O bloco except captura a TypeError e imprime a mensagem de erro associada:

can only concatenate str (not "int") to str

Finalmente, vamos disparar a ZeroDivisionError. Modifique a última linha novamente, desta vez tentando dividir por zero. Observe que a condição TypeError (dividend == 10) não é atendida.

## ... (rest of the code) ...
divide(dividend=20, divisor=0)

Execute o script:

python3 multiple_handler.py

O mesmo bloco except agora captura a ZeroDivisionError e imprime sua mensagem:

division by zero

Para que a verificação passe, certifique-se de que a chamada final no seu script seja divide(dividend=10, divisor=5) para disparar a TypeError.

O Bloco Finally no Tratamento de Exceções

Nesta etapa, você entenderá o propósito e o uso do bloco finally. O código dentro de uma cláusula finally é sempre executado, independentemente de uma exceção ter sido disparada ou tratada. Isso o torna ideal para operações de limpeza, como fechar um arquivo ou uma conexão de rede.

Vamos ver como funciona. Abra o arquivo finally_handler.py e adicione o seguinte código:

## bloco finally: sempre executa independentemente de exceções
def divide(dividend , divisor):
    try:
        print(dividend / divisor)
    except ZeroDivisionError:
        print('You can not divide by 0')
    finally:  ## Sempre executa, mesmo se ocorrer uma exceção
        print('Execution finished')

divide(dividend=10, divisor=5)

Execute o script a partir do seu terminal:

python3 finally_handler.py

Neste caso, nenhuma exceção ocorre. O bloco try é concluído com sucesso e, em seguida, o bloco finally é executado.

2.0
Execution finished

Agora, vamos introduzir um erro. Modifique a última linha em finally_handler.py para dividir por zero:

## ... (rest of the code) ...
divide(dividend=10, divisor=0)

Execute o script novamente:

python3 finally_handler.py

Desta vez, uma ZeroDivisionError é disparada e capturada pelo bloco except. Mesmo que uma exceção tenha ocorrido, o bloco finally ainda é executado após o término do bloco except.

You can not divide by 0
Execution finished

Como você pode ver, a mensagem "Execution finished" é impressa em ambos os cenários, demonstrando que o bloco finally é um local confiável para código que deve sempre ser executado.

Exceções Personalizadas

Nesta etapa, você aprenderá como criar suas próprias exceções personalizadas. Este é um recurso poderoso para tornar suas aplicações mais legíveis e fáceis de manter, pois você pode criar tipos de erro específicos que descrevem problemas exclusivos do domínio do seu programa.

Exceções personalizadas são definidas criando uma nova classe que herda da classe base Exception do Python. Você pode então disparar essa exceção usando a palavra-chave raise.

Abra o arquivo custom_exception.py e adicione o seguinte código para definir e disparar uma exceção personalizada simples:

## Exceção personalizada: criada herdando da classe Exception
class MyCustomException(Exception):
    pass

raise MyCustomException  ## Disparar a exceção personalizada

Se você executar este script, ele parará imediatamente e mostrará um traceback para sua nova exceção:

python3 custom_exception.py
Traceback (most recent call last):
  File "/home/labex/project/custom_exception.py", line 5, in <module>
    raise MyCustomException  ## Disparar a exceção personalizada
__main__.MyCustomException

Você também pode fornecer uma mensagem descritiva ao disparar uma exceção personalizada. Modifique custom_exception.py para passar uma string para sua exceção:

class MyCustomException(Exception):
    pass

raise MyCustomException('A custom message for my custom exception')

Executar isso mostrará sua mensagem no traceback:

Traceback (most recent call last):
  File "/home/labex/project/custom_exception.py", line 4, in <module>
    raise MyCustomException('A custom message for my custom exception')
__main__.MyCustomException: A custom message for my custom exception

O tratamento de uma exceção personalizada é feito da mesma forma que o tratamento de uma integrada: usando um bloco try...except. Atualize custom_exception.py para sua forma final, que dispara e trata a exceção personalizada:

class MyCustomException(Exception):
    pass

try:
    raise MyCustomException('A custom message for my custom exception')
except MyCustomException:
    print('My custom exception was raised')

Agora, execute o script pela última vez:

python3 custom_exception.py

O programa não trava mais. Em vez disso, ele executa o código no bloco except e imprime sua mensagem de confirmação:

My custom exception was raised

Resumo

Neste laboratório, você aprendeu as técnicas essenciais para o tratamento de exceções em Python. Você começou com os blocos básicos try e except para capturar erros específicos e evitar travamentos do programa. Em seguida, aprendeu como tratar eficientemente múltiplos tipos de exceções em um único bloco except. Você também explorou o bloco finally, que é crucial para códigos de limpeza que devem sempre ser executados. Finalmente, você adquiriu a capacidade de criar, disparar e tratar suas próprias exceções personalizadas, permitindo que você construa uma lógica de tratamento de erros mais robusta e descritiva em suas aplicações.