# ⚠️Exceptions

Em Python, uma "exception" (exceção) refere-se a um evento anormal ou <mark>erro</mark> que ocorre durante a execução de um programa. Essas exceções são eventos que interrompem o fluxo normal de execução do código (aquela mensagem chata de ERRO!), indicando que algo inesperado aconteceu. O tratamento de exceções em Python é realizado através de blocos `tryexcept`. Bora ver o que acontece quando colocamos 'string' (texto) como entrada para o programa que foi criado para receber números inteiros 👇.

```python
y = int(input("Número inteiro para 'y':"))
print(f"Y é {y}")
#gato
```

```markdown
---------------------------------------------------------------------------

<ValueError>: invalid literal for int() with base 10: 'gato'
```

Repare que gerou um erro, `ValueError` 👀, e para evitar essas mensagens, então bora melhorar o código usando 'exception' 👇.

```python
try:
    #código que pode gerar exceção
    y = int(input("Número inteiro para 'y':"))
except ValueError:
    #código para lidar com a exceção especifica
    print("y não é um número inteiro")
#gato
print(f"y é {y}")
```

Melhorou, mas veja 👆 que o `try` <mark>retorna um valor</mark> e dessa forma é possível colocar o `print()` logo após a variável 'y' ou chamá-la depois e não se trata de variável global ou local, também é 🔑 importante ter em conta que existem vários tipos de erros, 👉 [ler manual](https://docs.python.org/pt-br/3/library/exceptions.html#Exception).

```python
try:
    #código que pode gerar exceção
    y = int(input("Número inteiro para 'y':"))
except ValueError:
    #código para lidar com a exceção especifica
    print("y não é um número inteiro")
else:
    print(f"y é {y}")
```

Nesse anterior 👆 caso, o **else** está associado ao **try,** o try verifica e retorna um valor e se este for 'True' (verdadeiro ✅) vai para o else e executa o código. Bora utilizar um loop e só terminar o código quando cumprir o requisito.

```python
while True:
    try:
        y = int(input("Número inteiro para 'y':"))
    except ValueError:
        print("y não é um inteiro")
    else:
        break
print(f"y é {y}")
```

<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Sempre que vc for criar funções, na maioria das vezes, que elas retornem um valor <code>return</code> para poder trabalhar💼 com esses dados ✅.</div>
</div>

```python
def main():
    x = obt_int()
    print(f"x é {x}")

def obt_int():
    #esta função retorna um valor inteiro.
    while True:
        try:
            x = int(input("Valor para x:"))
        except ValueError:
            print("x não é um inteiro")
        else:
            break
    return x

main()
```

Ficou bem melhor, mas o python quase sempre permite você melhorar o código, menos linhas de código com o mesmo funcionamento. Lembre que o `try` <mark> retorna um valor</mark>, então podemos trazer o **return** direto para o *try* , desse jeito não precisamos mais do else, da seguinte forma 👇:

```python
def main():
    x = obt_int()
    print(f"x é {x}")

def obt_int():
    #esta função retorna um valor inteiro.
    while True:
        try:
            return int(input("Valor para x:"))
        except ValueError:
            print("x não é um inteiro")

main()
```

E para fazer mais reutilizável a função `obt_int()`, tirar o valor do input pq fica muito limitado, também pode-se utilizar um parâmetro chamado `pass` que simplesmente ignora essa linha e continua, da seguinte forma 👇:

```python
def main():
    x = obt_int("Valor para x: ")
    print(f"x é {x}")

def obt_int(prompt):
    #esta função retorna um valor inteiro.
    while True:
        try:
            return int(input(prompt))
        except ValueError:
            pass

main()
```
