Tratando exceções

Ver Todos os Exercícios

Teoria

Reconhecendo exceções

Cara, nem sempre a gente pode garantir que um código que a gente escreveu vai funcionar sempre. Imagina esse programa como exemplo, meramente ilustrativo:

Nosso programa de exemplo perguntar ao usuário um número e calcula quanto é 30 dividido por esse número. Depois, esse resultado é exibido pro usuário. Beleza! Mas, cara, se o usuário digitar 0 vai dar treta nisso aí! Apesar disso, nosso código não necessariamente tá errado, entende?! Acontece que existem casos onde o código falha. Existem exceções, e essa é a palavra do dia.

Sabendo reconhecer que nosso código pode ter exceções no seu funcionamento, a gente pode tratar essas exceções a nossa maneira!

Tratando exceções

Primeiramente, deixa eu te falar o que significa tratar exceções. Tá ligado que quando algum erro acontece, aparece aquelas letrinhas vermelhas com o erro?! Então... Tratar exceções significa que a gente quer tratar manualmente esses erros. Em vez das letrinhas vermelhas, o código vai executar.

Pra isso, vamos aprender três novas palavras-chave: try, except e finally. O código abaixo ilustra o esqueleto das estruturas de tratamento de exceções, mas ainda vou detalhar os usos das palavras-chave.

Palavra-chave try

A palavra try (“tentar”, em inglês) é usada pra criar um bloco de código que talvez dê errado. Essa palavra chave é a alma do tratamento de exceções. Só da pra gente tratar exceções que estão dentro do bloco try.

Palavra-chave except

A gente usa a palavra-chave except (“exceção”, em inglês) pra definir o que deve acontecer caso dê erro! Isso significa que o código dentro desse bloco não vai ser executado caso tudo dê certo. Repara que no código de exemplo, a gente usou um print() dizendo que não foi possível calcular o resultado e definimos a variável “resultado” pra zero. Esse código só é executado quando o código no bloco try der treta e não funcionar.

Se a gente colocar o except, igual na imagem acima, QUALQUER erro que der no código do try vai simplesmente chamar o bloco except. No entanto, a gente também consegue especificar o erro que a gente quer tratar!

Nesse código, a gente tá especificando que só quer tratar o erro da divisão por zero. Então, qualquer outro erro seria tratado normalmente pelo Python (malditas letrinhas vermelhas)..

Mas repara que pra especificar o erro que você quer tratar, é preciso especificar o nome do erro! E aí você me pergunta: “cara, como diabos eu vou saber o nome do erro?”.

Bom, o macete é você não decorar, mas provocar o erro de propósito pra copiar seu nome! Olha, vou colocar na primeira linha do meu código uma conta que com certeza vai dar o erro de divisão por zero.

Quando tentei executar...

Olha ele aí... Conseguimos descobrir o nome do erro provocando o erro propositalmente! Malandramente! Hahaha

Obs: eu tô usando o erro de divisão por zero como um exemplo. Na verdade, essa estrutura funciona pra qualquer tipo de erro. Vou usar um outro erro pra exemplificar. Repara que a gente tá convertendo o resultado da função input() pra inteiro, mas caso o cara não digite um número, vai dar erro! Vamos descobrir qual o nome do erro.

Quando executei...

Pronto! Descobrimos que o nome desse erro é ValueError. Vamos especificar que nosso bloco exception só vai tratar esses dois tipos de erro agora...

Show! Agora, o bloco except vai tratar os dois casos: se o usuário digitar um número invalido ou se digitar zero. Por último, repara que dessa vez eu coloquei o linha que tem a função int(input()) dentro do bloco try. Isso porque só da pra gente tratar erros que acontecem dentro do bloco try, sacou?!

Palavra-chave finally

No bloco que a gente cria com a palavra-chave finally (“finalmente”, em inglês), o código vai ser executado SEMPRE. Independente de dar erro ou não no bloco try, o bloco finally vai ser executado no fim. Se o bloco try der erro, o bloco except vai ser executado ANTES do finally. Sacou?!

Na real, a ideia do bloco finally é garantir que o código vai ser executado. Depois que o erro aconteceu, pode ser que o programa siga firme e forte se você tratar aquela exceção, mas pode ser que o programa pare e dê aquele errinho das letras vermelhas. Independente disso, o bloco finally vai ser executado SEMPRE, ok?!

Usando só dois blocos

Beleza, agora que sacamos a utilidade dos três blocos, se liga que não é obrigatório a gente usar os três.

Olha, dessa forma a variável “resultado” vira zero caso dê algum erro no bloco try, mas não construímos nenhum bloco finally. Isso é ok! Assim como também é possível fazer o contrário. Olha de novo esse caso:

Se o número digitado for 0, a gente sabe que vai dar erro. Mas quando um erro ocorre, o programa imediatamente para.

Reparou que o último print() não foi executado?! Isso não acontece quando usamos o bloco finally, porque o que tá dentro do finally SEMPRE é executado, independente do que acontece no try.

O resultado:

Como não tratamos o erro no except, deu erro da mesma forma. Mas repara que mesmo assim o print() foi executado. Viu?!

Pra você mandar super bem na sua prova, é importante fazer os exercícios de fixação, ok?! To te esperando lá!

Palavra-chave finally

Usando só dois blocos

Exercícios Resolvidos

Exercício Resolvido #1

Observe o seguinte programa:

Qual exceção será gerada durante a sua execução ?

Passo 1

Podemos observar com facilidade que o módulo math foi importado incorretamente ao utilizarmos o nome mathematics e por esse motivo que uma exceção é gerada.

Resposta

Logo, por termos uma única importação incorreta em nosso código, podemos afirmar que a exceção gerada é: ImportError.

Exercício Resolvido #2

Observe o seguinte programa:

Escreva o que será impresso na tela caso o mesmo seja executado com o seguinte arquivo de entrada:

Passo 1

Bom, vamos lá!

A primeira coisa que nós iremos fazer é analisar o arquivo de entrada desse programa (program.in).

Com isso, sabemos que o programa terá a entrada de dois números, que são: 5 e 3.

Passo 2

Agora que já sabemos quais são as entradas, podemos executarmos o programa em busca de exceções.

Dentro de um bloco try o programa irá requisitar a entrada de dois números do tipo float para as variáveis n 1 e n 2 , sem problemas até aqui, uma vez que 5 e 3 estão presentes no conjunto dos números reais.

Passo 3

Em seguida, uma variável r e s u l t a d o recebe o resultado da divisão entre n 1 e n 2 . Mais uma vez, tudo está tranquilo.

Passo 4

Por fim, temos a impressão da variável r e s u l t com precisão de duas casas decimais.

PERA!

Nós não temos uma variável r e s u l t e sim uma variável r e s u l t a d o . Logo, uma exceção será gerada, mais precisamente a exceção NameError.

Passo 5

Agora ficou fácil, só nos resta analisarmos as exceções que foram tratadas.

Nós temos o tratamento de exceções do tipo ValueError, ZeroDivisionError e uma para todas as outras exceções.

Como a nossa exceção não é nem do tipo ValueError quanto do tipo ZeroDivisionError, o que será impresso na tela é aquilo executado no bloco onde temos apenas except.

Resposta

Portanto, o que será impresso na tela é: “Algo deu errado.”

Exercício Resolvido #3

Um colega de classe tentou executar o seguinte programa:

E obteve a seguinte mensagem de erro:

Sem entender muito bem o significado dessa mensagem, ele decidiu pedir ajuda a você que estuda programação pelo Responde Aí.

Reescreva o código feito por ele de uma forma com que esse erro seja exibido de uma forma mais clara e amigável, e, consequentemente, possa ser resolvido pelo próprio colega.

Passo 1

Muito simples!

Ao observarmos a mensagem de erro, já sabemos de cara que devemos simplesmente tratar uma exceção FileNotFoundError.

Passo 2

Sendo assim, basta colocarmos o código dentro de um bloco try e, dentro de um bloco except para a exceção FileNotFoundError, escrevermos uma mensagem mais clara:

Resposta

Portanto, ao invés do nosso colega ter que decifrar o erro, ele saberá de cara que o arquivo o qual está tentando abrir não existe.

Exercício Resolvido #4

Observe o seguinte programa:

Um dos problemas do código acima é que o mesmo além de possuir um erro lógico (execução de um comando de escrita em um arquivo em modo de leitura), abre um arquivo e tem a sua execução encerrada.

Incremente o código apresentado liberando da memória a referência do arquivo tanto nos casos de erro, quanto em execuções bem-sucedidas (caso o mesmo fosse aberto em modo de escrita).

Passo 1

Bom, a primeira coisa que devemos fazer é analisar o que o enunciado quer que nós façamos.

Quando o mesmo diz que devemos liberar da memória a referência do arquivo aberto, ele está nos dizendo que devemos utilizar a função close. Porém, isso deve ser feito “tanto nos casos de erro, quanto em execuções bem-sucedidas (caso o mesmo fosse aberto em modo de escrita).”

Passo 2

Sendo assim, podemos utilizar o comando finally, uma vez que ele será sempre executado, ou seja, tanto quando o bloco try não gerar exceções, quanto após a execução de algum bloco except.

Resposta

Portanto, após o incremento do bloco finally o programa ficará da seguinte forma: