Erros e Exceções
Erros e exceções são muito importantes no desenvolvimento de uma aplicação, pois eles dizem ao usuário se algo não saiu como esperado, ou para o desenvolvedor se algo está errado, nessa seção aprenderemos sobre Stack Tracing ("Análise da Stack"), conheceremos os erros nativos da linguagem, aprenderemos a criar nosso próprios erros e veremos sobre depuração (debugging).
Mas antes devo explicar qual a diferença entre Erro e Exceção.
O que seria um Erro?
Um erro é todo e quaisquer problema que impede a execução do programa.
Geralmente ocorrem em tempo de compilação, em Python o único erro possível é o de se Sintaxe.
Você geralmente não lida com erros e eles são irreversíveis, então geralmente quando eles ocorrem a aplicação é terminada.
O que seria uma Exceção?
Uma exceção é um tipo de erro que ocorre em tempo de execução
Normalmente são erros do próprio programador durante o desenvolvimento, eles não finalizam o programa, mas podem trazer comportamento inexperado para a aplicação.
Geralmente são chamados de Erros lógicos.
Stack Tracing ("Análise da Stack")
Stack Tracing consiste em analisar a saída do terminal em busca da origem do erro, essa saida também pode ser chamada de "Stack Backtrace" ou "Stack Traceback".
considere o seguinte código:
(Este código resultará em um erro)
1def a():
2 i = 0
3 j = b(i)
4 return j
5
6def b(z):
7 k = 5
8 if z == 0:
9 c()
10 return k + z
11
12def c():
13 error()
14
15a()
16
executando este código temos a seguinte saida:
1Traceback (most recent call last): 2 File "tb.py", line 15, in <module> 3 a() 4 File "tb.py", line 3, in a 5 j = b(i) 6 File "tb.py", line 9, in b 7 c() 8 File "tb.py", line 13, in c 9 error() 10NameError: name 'error' is not defined 11
vamos "desmembrar" essa saida para podermos fazer a análise.
temos 3 elementos principais:
- O indicador de traceback
- A arvore de chamadas (CallStack)
- O erro que iniciou todo o processo de traceback e seu tipo.
O indicador de traceback diz que as proximas linhas fazem referencia a um traceback, ele é facilmente indentificado por normalmente constar palavras e sentenças como "Stack Trace", "Traceback", "Panicked", "Panicking", etc.
no nosso exemplo ele seria a primeira linha: Traceback (most recent call last)
.
esse "most recent call last" diz que a ultima chamada da CallStack é a mais recente.
A arvore de chamadas contém a ordem que os elementos foram executados até chegar ao erro, observemos nosso exemplo:
1File "tb.py", line 15, in <module> 2 a() 3File "tb.py", line 3, in a 4 j = b(i) 5File "tb.py", line 9, in b 6 c() 7File "tb.py", line 13, in c 8 error() 9
O erro foi acionado na função c
presente na linha 13, que por sua vez foi chamada pela função b
na linha 9, que então foi chamada pela função a
na linha 3, que por fim foi executada na linha 15 diretamente no arquivo.
perceba que nós temos um passo-a-passo de chamadas até indentificarmos a origem do erro. Isso se torna excepcionalmente útil para descobrirmos a origem de um erro.
E por fim o erro que iniciou todo esse processo se encontra ao final da traceback: NameError: name 'error' is not defined
perceba que ele além de conter o erro, contém também seu tipo, que no nosso caso é um NameError
, isso é bastante importante e útil para sabermos como consertar, pois sabendo o tipo de erro/exceção poderemos pensar na melhor solução para o problema, além de podermos lidar com ele usando um bloco try-except
, que veremos mais a frente.
Erros e exceções nativas
Esses erros e exceções já estão presentes e definidos na linguagem, são erros comuns e genéricos, normalmente associados a questões da linguagem mesmo. Antes de prover uma lista com os mais comuns/úteis, devo explicar a heirarquia de erros.
Todas as exceções em Python são classes que herdam caracteristicas de 5 classes base, sendo essas as classes:
-
BaseException
-
Exception
-
ArithmeticError
-
BufferError
-
LookupError
BaseExeption
Essa classe é a base de todas as outras exceções e erros em Python e NÃO deve ser usada como base para exceções definidas pelo usuário, pois exceções que são baseadas nesta normalmente são associadas com terminar o programa, ou seja, se tivermos erros do usuário baseados nela e nós lidarmos com esses erros, podemos acidentalmente impedir que o programa possa ser finalizado por exemplo.
Exception
Essa é a classe base para todas as exceções que não terminam com a execução do programa e todos os erros definidos pelo usuário também devem herdar desta classe.
ArithmeticError
Essa é a classe base para todas as exceções que lidam com erros artiméticos.
BufferError
Essa exceção é usada quando temos algum problema envolvendo operações com buffers
LookupError
Base para todos os erros que envolvem mapeamento inválido de chaves ou indexes.
Hierarquia de Exceções
- BaseException
- SystemExit
- KeyboardInterrupt
- GeneratorExit
- Exception
- StopIteration
- StopAsyncIteration
- ArithmeticError
- FloatingPointError
- OverflowError
- ZeroDivisionError
- AssertionError
- AttributeError
- BufferError
- EOFError
- ImportError
- ModuleNotFoundError
- LookupError
- IndexError
- KeyError
- MemoryError
- NameError
- UnboundLocalError
- OSError
- BlockingIOError
- ChildProcessError
- ConnectionError
- BrokenPipeError
- ConnectionAbortedError
- ConnectionRefusedError
- ConnectionResetError
- FileExistsError
- FileNotFoundError
- InterruptedError
- IsADirectoryError
- NotADirectoryError
- PermissionError
- ProcessLookupError
- TimeoutError
- ReferenceError
- RuntimeError
- NotImplementedError
- RecursionError
- SyntaxError
- IndentationError
- TabError
- IndentationError
- SystemError
- TypeError
- ValueError
- UnicodeError
- UnicodeDecodeError
- UnicodeEncodeError
- UnicodeTranslateError
- UnicodeError
- Warning
- DeprecationWarning
- PendingDeprecationWarning
- RuntimeWarning
- SyntaxWarning
- UserWarning
- FutureWarning
- ImportWarning
- UnicodeWarning
- BytesWarning
- EncodingWarning
- ResourceWarning
Irei explicar cada erro, se você não entender de cara, tudo bem, existem erros sobre questões mais avançadas como corrotinas, entre outras, isso servirá mais como um guia consultas futuras.
SystemExit
Esta exceção é levantada pela função sys.exit()
. Ele herda de BaseException
em vez de Exception
para que não seja acidentalmente capturado pelo código que captura Exception
. Isso permite que a exceção se propague corretamente e faça com que o interpretador saia. Quando não é tratado, o interpretador Python sai e nenhum traceback é impresso.
O construtor aceita o mesmo argumento opcional passado para sys.exit()
. Se o valor for um inteiro, ele especifica o status de saída do sistema; se for None
, o status de saída é 0; se tiver outro tipo (como uma string), o valor do objeto é exibido e o status de saída é 1.
KeyboardInterrupt
Levantada quando um usuário aperta a tecla de interrupção (normalmente Control-C ou Delete). Durante a execução, uma checagem de interrupção é feita regularmente. A exceção herda de BaseException
para que não seja capturada acidentalmente por códigos que tratam Exception
e assim evita que o interpretador saia.
GeneratorExit
Levantado quando um gerador ou uma corrotina está fechado(a). Herda diretamente de BaseException
em vez de Exception
, já que tecnicamente não é um erro.
StopIteration
Levantada pela função embutida next()
e o método __next__()
de um iterador para sinalizar que não há mais itens produzidos pelo iterador.
O objeto exceção tem um único atributo value
, que é fornecido como um argumento ao construir a exceção, e o padrão é None
.
Quando uma função geradora ou corrotina retorna, uma nova instância StopIteration
é levantada, e o valor retornado pela função é usado como o parâmetro value
para o construtor da exceção.
Se um código gerador direta ou indiretamente levantar StopIteration
, ele é convertido em uma RuntimeError
(mantendo o StopIteration
como a nova causa da exceção).
StopAsyncIteration
Deve ser levantada pelo método __anext__()
de um objeto iterador assíncrono para parar a iteração.
FloatingPointError
Não usado atualmente.
OverflowError
Levantada quando o resultado de uma operação aritmética é muito grande para ser representada. Para inteiros normalmente se é levantado MemoryError
.
ZeroDivisionError
Levantada quando o segundo argumento de uma divisão ou operação de módulo é zero. O valor associado é uma string que indica o tipo dos operandos e a operação.
AssertionError
Levantado quando uma instrução assert
falha.
AttributeError
Levantado quando uma referência de atributo ou atribuição falha. (Quando um objeto não oferece suporte a referências ou atribuições de atributos, TypeError é levantado.)
BufferError
Levantado quando uma operação relacionada a buffer não puder ser realizada.
EOFError
Levantado quando a função input()
atinge uma condição de fim de arquivo (EOF) sem ler nenhum dado.
ImportError
Levantada quando a instrução import
tem problemas ao tentar carregar um módulo. Também é gerado quando o “from list”
em from ... import
tem um nome que não pode ser encontrado.
ModuleNotFoundError
Uma subclasse de ImportError
que é levantada por import
quando um módulo não pôde ser localizado. Também é levantada quando None
é encontrado em sys.modules
.
IndexError
Levantada quando um índice de alguma sequência está fora do intervalo. (Índices de fatia são truncados silenciosamente para cair num intervalo permitido; se um índice não for um inteiro, TypeError é levantada.)
KeyError
Levantada quando uma chave de mapeamento (dicionário) não é encontrada no conjunto de chaves existentes.
MemoryError
Levantada quando uma operação fica sem memória mas a situação ainda pode ser recuperada (excluindo alguns objetos). O valor associado é uma string que indica o tipo de operação (interna) que ficou sem memória.
NameError
Levantada quando um nome local ou global não é encontrado. Isso se aplica apenas a nomes não qualificados. O valor associado é uma mensagem de erro que inclui o nome que não pode ser encontrado.
UnboundLocalError
Levantada quando uma referência é feita a uma variável local em uma função ou método, mas nenhum valor foi vinculado a essa variável. Esta é uma subclasse de NameError
.
OSError
Esta exceção é levantada quando uma função do sistema retorna um erro relacionado ao sistema, incluindo falhas do tipo E/S como "arquivo não encontrado" ou "disco cheio" (não para tipos de argumentos não permitidos ou outro erro acessório).
BlockingIOError
Levantada quando uma operação irá bloquear um objeto (ex: soquete) que está configurado para modo de "não-bloqueio"
ChildProcessError
Levantada quando uma operação em um processo filho retorna um erro.
ConnectionError
Uma classe base para problemas relacionados à conexão
BrokenPipeError
Levantado quando tentamos escrever em uma conexão onde a outra ponta está fechada, quando o soquete está fechado somente para escrita.
ConnectionAbortedError
Levantado quando uma tentativa de conexão é abortada pelo par.
ConnectionRefusedError
Levantado quando uma tentativa de conexão é recusada pelo par.
ConnectionResetError
Levantado quando uma tentativa de conexão é reiniciada pelo par.
FileExistsError
Levantado quando tenta-se criar um diretorio ou arquivo existente.
FileNotFoundError
Levantado quando um diretorio ou arquivo requisitado não existe.
InterruptedError
Levantada quando uma chamada do sistema é interrompida por um sinal de entrada.
IsADirectoryError
Levantada quando uma operação de arquivo é executada em um diretório.
NotADirectoryError
Levantada quando uma operação de diretório é executada em algo que não é um diretório.
PermissionError
Levantada quando uma operação não tem as permissões adequadas.
ProcessLookupError
Levantada quando um determinado processo não existe.
TimeoutError
Levantada quando uma função do sistema atinge o tempo limite.
ReferenceError
Esta exceção é levantada quando um intermediário de referência fraca, criado pela função weakref.proxy()
, é usado para acessar um atributo do referente após ter sido coletado como lixo.
RuntimeError
Levantada quando um erro é detectado e não se encaixa em nenhuma das outras categorias. O valor associado é uma string indicando o que precisamente deu errado.
NotImplementedError
Em classes base, definidas pelo usuário, os métodos abstratos devem gerar essa exceção quando requerem que classes derivadas substituam o método, ou enquanto a classe está sendo desenvolvida, para indicar que a implementação real ainda precisa ser adicionada.
RecursionError
É levantada quando o interpretador detecta que a profundidade máxima de recursão foi excedida.
SyntaxError
Levantada quando o analisador encontra um erro de sintaxe. Isso pode ocorrer em uma instrução import, em uma chamada às funções embutidas compile()
, exec()
ou eval()
, ou ao ler o script inicial ou entrada padrão (também interativamente)
IndentationError
Classe base para erros de sintaxe relacionados a indentação incorreta.
TabError
Levantada quando o indentação contém um uso inconsistente de tabulações e espaços.
SystemError
Levantada quando o interpretador encontra um erro interno, mas a situação não parece tão grave para fazer com que perca todas as esperanças. O valor associado é uma string que indica o que deu errado (em termos de baixo nível).
TypeError
Levantada quando uma operação ou função é aplicada a um objeto de tipo inadequado. O valor associado é uma string
que fornece detalhes sobre a incompatibilidade de tipo.
Essa exceção pode ser levantada pelo código do usuário para indicar que uma tentativa de operação em um objeto não é suportada e não deveria ser. Se um objeto deve ter suporte a uma dada operação, mas ainda não forneceu uma implementação, NotImplementedError
é a exceção apropriada a ser levantada.
Passar argumentos do tipo errado (por exemplo, passar uma list
quando um int
é esperado) deve resultar em uma TypeError
, mas passar argumentos com o valor errado (por exemplo, um número fora limites esperados) deve resultar em um ValueError
.
ValueError
Levantada quando uma operação ou função recebe um argumento que tem o tipo certo, mas um valor inadequado, e a situação não é descrita por uma exceção mais precisa, como IndexError
.
UnicodeError
Levantada quando ocorre um erro de codificação ou decodificação relacionado ao Unicode.
UnicodeDecodeError
Levantada quando ocorre um erro relacionado ao Unicode durante a codificação.
UnicodeEncodeError
Levantada quando ocorre um erro relacionado ao Unicode durante a decodificação.
UnicodeTranslateError
Levantada quando ocorre um erro relacionado ao Unicode durante a tradução.
Warning
Classe base para categorias de aviso.
DeprecationWarning
Classe base para avisos sobre recursos descontinuados quando esses avisos se destinam a outros desenvolvedores Python.
PendingDeprecationWarning
Classe base para avisos sobre recursos que foram descontinuados e devem ser descontinuados no futuro, mas não foram descontinuados ainda.
RuntimeWarning
Classe base para avisos sobre comportamento duvidoso de tempo de execução.
SyntaxWarning
Classe base para avisos sobre sintaxe duvidosa.
UserWarning
Classe base para avisos gerados pelo código do usuário.
FutureWarning
Classe base para avisos sobre recursos descontinuados quando esses avisos se destinam a usuários finais de aplicações escritas em Python.
ImportWarning
Classe base para avisos sobre prováveis erros na importação de módulos.
UnicodeWarning
Classe base para avisos relacionados a Unicode.
BytesWarning
Classe base para avisos relacionados a bytes
e bytearray
.
EncodingWarning
Classe base para avisos relacionados a codificações.
ResourceWarning
Classe base para avisos relacionados a uso de recursos.
Elevando erros
Elevar um erro consiste em voluntariamente executar um erro, para tal nós usamos a keyword raise
, para os erros nativos podemos passar uma string que servirá de mensagem, a sintaxe seria assim:
1raise TipoDeErro("mensagem")
2
veja o exemplo:
1raise TypeError("Tipo errado de dado")
2
Saida
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) /media/Arquivos/Programming/Lessons/PythonLessons/Classes/5-Erros.ipynb Cell 11 in <cell line: 1>() ----> <a href='vscode-notebook-cell:/media/Arquivos/Programming/Lessons/PythonLessons/Classes/5-Erros.ipynb#X13sZmlsZQ%3D%3D?line=0'>1</a> raise TypeError("Tipo errado de dado") TypeError: Tipo errado de dado