Erros
Como evitar erros de entrada de usuário
Voltando ao programa C2F:
import sys
C = float(sys.argv[1])
F = 5./9*C + 32
print F
Nosso programa para com uma mensagem de erro estranha quando não é passado nada como argumento de linha de comando:
Terminal> python c2f.py
Traceback (most recent call last):
File "c2f.py", line 2, in ?
C = float(sys.argv[1])
IndexError: list index out of range
Porque?
- O usuário esquece de escrever o argumento de linha de comando;
sys.argv
então possui apenas um elemento,sys.argv[0]
, que é o nome do programac2f.py
;- Índice 1, em
sys.argv[1]
, aponta para um elemento inexistente na listasys.argv
; - Qualquer índice correspondente a um elemento inexistente leva a um
IndexError
.
Nós devemos manipular erros de entrada!
Como podemos ter controle, explicar o que está errado na entrada e parar o programa sem uma mensagem de erro estranha?
## Program c2f_ctrl.py
import sys
if len(sys.argv) < 2:
print 'Você não passou nenhum argumento na linha de comando!'
sys.exit(1) ## abortando
F = 9.0*C/5 + 32
print '%gC is %.1fF' % (C, F)
Terminal> python c2f_ctrl.py
Você não passou nenhum argumento na linha de comando!
Exceções como uma alternativa para ramificações
Ao invés de testar se algo está errado, recuperar do erro e fazer o que era para ser feito é comum em python (e muitas outras linguagens) tentar fazer o que deveria ser feito e se falhar, recuperar do erro.
Esse princípio faz o uso do bloco try-except
try:
<declarações que queremos executar>
except:
<declarações para manipular erros>
Se algo vai errado no bloco try
, o Python levanta uma exceção e a execução pula imediatamente para o bloco except
.
O programa de conversão de temperatura com try-except
Tente ler C
da linha de comando, se falhar, avise ao usuário e aborte a execução. Salve como c2f_try_except.py:
import sys
try:
C = float(sys.argv[1])
except:
print 'Você falhou ao passar um argumento de linha de comando!'
sys.exit(1) ## aborta
F = 9.0*C/5 + 32
print '%gC is %.1fF' % (C, F)
Execução:
Terminal> python c2f_try_except.py
Você falhou ao passar um argumento de linha de comando!
Terminal> python c2f_try_except.py 21C
Você falhou ao passar um argumento de linha de comando!
Um bom estilo de programação testa por exceções específicas
try:
C = float(sys.argv[1])
except IndexError:
print 'Você falhou ao passar um argumento de linha de comando!'
Se tivermos um índice fora dos limites em sys.argv
uma exceção IndexError
é levantada e a execução salta automaticamente para o bloco except
.
Se qualquer outra exceção for levantada, o Python aborta a execução.
Terminal> python c2f_try_except.py 21C
Traceback (most recent call last):
File "c2f_try_except.py", line 3, in <module>
C = float(sys.argv[1])
ValueError: invalid literal for float(): 21C
Testando para as exceções IndexError
e ValueError
import sys
try:
C = float(sys.argv[1])
except IndexError:
print 'Nenhum argumento na linha de comando para C!'
sys.exit(1) ## abort execution
except ValueError:
print 'Graus Celsius devem ser um número, não "%s"' % sys.argv[1]
sys.exit(1)
F = 9.0*C/5 + 32
print '%gC é %.1fF' % (C, F)
Execuções:
Terminal> python c2f_try_except.py
Nenhum argumento na linha de comando para C!
Terminal> python c2f_try_except.py 21C
Graus Celsius devem ser um número, não "21C"
O programador pode levantar exceções
Ao invés de simplesmente deixar o Python levantar exceções, nós podemos levantar a nossa própria e adaptar a mensagem do problema em mãos.
Dois exemplos:
- pegando uma exceção, mas levantando uma nova exceção com uma mensagem de erro melhorada;
- levantando uma exceção por causa de entrada de dados errada.
Sintaxe básica: raise ExceptionType(mensagem)
Exemplos no levantamento de exceções com mensagens melhores
def ler_C():
try:
C = float(sys.argv[1])
except IndexError:
## levantando novamente, mas com explicação específica:
raise IndexError(
'Graus Celsius dever ser fornecidos na linha de comando')
except ValueError:
## levantando novamente, mas com explicação específica:
raise ValueError(
'Graus Celsius devem ser um número, não "%s"' % sys.argv[1])
## C pode ser lido como corretamente como número, mas com valor errado:
if C < -273.15:
raise ValueError('C=%g não é um valor físico!' % C)
return C
Chamando a função anterior e rodando o programa
try:
C = ler_C()
F = 9.0*C/5 + 32
print '%gC é %.1fF' % (C, F)
except (IndexError, ValueError) as e:
## mostre a exceção e pare o programa
print e
sys.exit(1)
Execuções:
Terminal> c2f_try_except.py
Graus Celsius dever ser fornecidos na linha de comando
Terminal> c2f_try_except.py 21C
Graus Celsius devem ser um número, não "21C"
Terminal> c2f_try_except.py -500
C=-500 não é um valor físico!
Terminal> c2f_try_except.py 21
21C é 69.8F