# Exceções e Tratamento de Erros

<figure><img src="https://1443919672-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIb0aHuNFbONG3bs5Njrl%2Fuploads%2FTi4uBu9kSz4NDU4qS7Xb%2Fimage.png?alt=media&#x26;token=3e86c94d-fa11-41a0-a364-e57e62e5e6b5" alt=""><figcaption><p>Doe, ajude a continuar criando conteúdo</p></figcaption></figure>

No desenvolvimento de qualquer aplicação, é inevitável que erros ocorram. Em Python, esses erros são chamados de **exceções**, e saber como tratá-los corretamente é crucial para garantir que o programa continue funcionando de forma estável, mesmo quando algo inesperado acontece.

Neste capítulo, vamos entender o que são exceções, como tratá-las, e as boas práticas para lidar com erros em seus programas Python.

**O que são Exceções?**

Exceções são eventos indesejados que ocorrem durante a execução de um programa, interrompendo seu fluxo normal. Elas podem acontecer por diversos motivos, como erros de digitação, operações inválidas ou problemas externos, como a falta de conexão com a internet. Python fornece um mecanismo robusto para lidar com essas situações e evitar que o programa "quebre".

Alguns exemplos comuns de exceções são:

* **`ZeroDivisionError`**: Quando se tenta dividir um número por zero.
* **`ValueError`**: Quando se tenta converter um tipo de dado inadequado.
* **`FileNotFoundError`**: Quando um arquivo que deveria ser aberto não existe.

Veja um exemplo de exceção gerada ao tentar dividir por zero:

```python
print(10 / 0)
```

Saída:

```
ZeroDivisionError: division by zero
```

Esse erro interrompe a execução do programa. No entanto, podemos evitar que ele encerre o programa abruptamente utilizando o tratamento de exceções.

**Tratamento de Exceções com `try` e `except`**

O tratamento de exceções em Python é feito com as palavras-chave `try`, `except`, `else` e `finally`. O bloco `try` contém o código que pode causar uma exceção, e o bloco `except` contém o que deve ser feito se ocorrer um erro.

Exemplo de tratamento de uma divisão por zero:

```python
try:
    resultado = 10 / 0
except ZeroDivisionError:
    print("Erro: divisão por zero não é permitida.")
```

Saída:

```
Erro: divisão por zero não é permitida.
```

Neste caso, o programa captura a exceção e exibe uma mensagem personalizada, sem interromper a execução.

**Tratando Exceções Específicas**

Cada tipo de exceção em Python tem um nome específico, como `ZeroDivisionError`, `ValueError`, ou `FileNotFoundError`. Podemos capturar exceções específicas para tratá-las de maneira apropriada.

Exemplo de captura de diferentes exceções:

```python
try:
    numero = int(input("Digite um número: "))
    resultado = 10 / numero
except ZeroDivisionError:
    print("Erro: não é possível dividir por zero.")
except ValueError:
    print("Erro: valor inválido, por favor insira um número.")
```

Se o usuário inserir um valor não numérico, a exceção `ValueError` será capturada, enquanto a tentativa de dividir por zero será tratada pelo `ZeroDivisionError`.

**Bloco `else` e `finally`**

Além do `try` e `except`, Python também oferece os blocos `else` e `finally` para complementar o tratamento de exceções:

* **`else`**: Executa um bloco de código caso nenhuma exceção ocorra no `try`.
* **`finally`**: Executa um bloco de código independentemente de ocorrer ou não uma exceção. Ele é útil para liberar recursos ou realizar ações de limpeza.

Exemplo:

```python
try:
    numero = int(input("Digite um número: "))
    resultado = 10 / numero
except ZeroDivisionError:
    print("Erro: divisão por zero.")
except ValueError:
    print("Erro: valor inválido.")
else:
    print(f"O resultado é {resultado}")
finally:
    print("Fim da execução.")
```

Saída (quando o usuário insere `2`):

```
O resultado é 5.0
Fim da execução.
```

Se não houver erros, o bloco `else` será executado, e o bloco `finally` sempre será executado, independentemente do que aconteça.

**Levantando Exceções com `raise`**

Além de capturar exceções, você também pode **levantar** exceções manualmente usando a palavra-chave `raise`. Isso pode ser útil quando você deseja verificar condições específicas no seu código e garantir que ele se comporte de uma determinada maneira em caso de erro.

Exemplo:

```python
def verifica_idade(idade):
    if idade < 18:
        raise ValueError("Idade não permitida, é necessário ser maior de idade.")
    return "Acesso permitido."

try:
    print(verifica_idade(16))
except ValueError as e:
    print(f"Erro: {e}")
```

Saída:

```
Erro: Idade não permitida, é necessário ser maior de idade.
```

Aqui, levantamos uma exceção personalizada com `raise` para garantir que o usuário tenha idade suficiente.

**Boas Práticas no Tratamento de Exceções**

Algumas boas práticas ao trabalhar com exceções em Python incluem:

1. **Especifique exceções**: Evite capturar todas as exceções com um `except` genérico. Especificar exceções como `ZeroDivisionError` ou `ValueError` ajuda a lidar com erros de maneira mais eficaz.
2. **Não silencie exceções**: Não ignore exceções sem fazer nada. Isso pode tornar o código mais difícil de depurar.
3. **Use o `finally` para limpeza**: Sempre use o bloco `finally` para garantir que recursos como arquivos ou conexões de rede sejam liberados, independentemente de ocorrerem erros.
4. **Forneça mensagens de erro úteis**: Ao capturar uma exceção, informe o motivo e possíveis soluções para o usuário ou desenvolvedor.

**Conclusão**

O tratamento de exceções é uma habilidade essencial no desenvolvimento de qualquer aplicação robusta e estável. Com os blocos `try`, `except`, `else`, `finally` e o uso adequado de `raise`, você pode prever e lidar com erros de maneira eficaz, garantindo que seu programa continue funcionando sem interrupções inesperadas.
