Erros e Manipulação de Exceções em Python
Erro e Exceções em Python
Existem duas grandes “categorias” de erros que podem ocorrer em um programa:
- Erros de Sintaxe
- Exceções ou Erros Lógicos
Erros de Sintaxe são erros que ocorrem quando um código não segue as regras formais da linguagem usada – por exemplo, esquecer de fechar chaves em blocos de código, ponto-e-vírgula no final de declarações, usar palavras-chave com grafia incorreta e, no caso do Python, não empregar identação adequada, entre outras.
São erros detectados no momento em que tentamos rodas a aplicação, e de resolução muito simples.
Já as Exceções, ou Erros Lógicos, ocorrem quando o programa é executado de uma forma que possa gerar um problema não previsto durante seu desenvolvimento, mesmo com a sintaxe perfeita. Por exemplo, tentar entrar com strings de texto no lugar de números em cálculos aritméticos, acessar recursos inexistentes de rede ou bancos de dados, ou realizar operações proibidas, como a famigerada divisão por zero.
As exceções são eventos especiais – geralmente erros – que ocorrem em tempo de execução. Quando um erro desses ocorre, o Python cria um objeto do tipo Exception.
Este objeto deve ser manipulado corretamente, caso contrário apenas imprimirá na tela um traceback do erro com alguns detalhes técnicos a respeito, além de parar inesperadamente a execução do script (trava o programa ou o finaliza) – o que não ajuda o usuário em praticamente nada.
As técnicas de manipulação de exceções permitem que os programadores criem aplicações que conseguem manipular as exceções (resolver os erros que porventura ocorram durante sua execução).
Uma das grandes vantagens de manipular corretamente as exceções é a possibilidade do programa continuar a rodar mesmo após a ocorrência de um erro, ou se isto não for possível devido a um erro grave, notificar o usuário de que um erro ocorreu e que o programa será encerrado, de forma mais graciosa do que simplesmente travar e ser fechado abruptamente.
Chamamos o processo de capturar e apresentar um erro de “lançar uma exceção (‘throw an exception‘)” ou “levantar uma exceção (‘raise an exception‘)”
Existem muitas exceções internas (built-in) no Python que são lançadas quando um erro específico ocorre. Por exemplo, uma exceção ImportError é lançada quando um módulo importado pelo script não é encontrado.
Podemos visualizar todas as exceções internas com a função local():
print(dir(locals()['__builtins__']))
Resultado:
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip'] ** Process exited - Return Code: 0 ** Press Enter to exit terminal
E também consultá-las na documentação oficial (seção “Concrete Exceptions”) para entender em detalhes o que faz cada uma delas: https://docs.python.org/3/library/exceptions.html
Manipulação de Exceções
Manipulamos as exceções no Python com as declarações try, except, else e finally.
A manipulação é feita em duas grandes etapas:
- Capturar uma exceção, que é detectar se uma exceção ocorreu; e
- Tratar a exceção, que significa tomar uma ação apropriada para minimizar ou resolver o problema ocorrido.
A principal declaração para tratamento de exceções é a declaração try. Colocamos o código da operação crítica que pode levantar uma exceção dentro de um bloco try.
Em um bloco except colocamos o código que deve tratar a exceção, caso ocorra.
Exemplo: capturar exceções genéricas
# importamos o módulo sys para visualizarmos o tipo da exceção import sys item = 0 # testar tb com 22 e 'Bóson' # Descomente a linha a seguir para ver o que ocorre quando não há manipulação das exceções. #divisao = 1 / item try: divisao = 1/item print("Valor:", item) print("1 dividido por", item, "é", divisao) except: print("Ocorreu a exceção", sys.exc_info()[0]) print()
Ocorreu a exceção <class 'ZeroDivisionError'>
Capturar exceções específicas
Podemos capturar exceções específicas usando classes apropriadas, caso saibamos de antemão o tipo de erro que pode vir a a ocorrer no script, como por exemplo erros de tipo incorreto ou a clássica divisão por zero.
Assim, podemos dar um tratamento adequado a cada caso de erro que ocorra.
import sys item = 0 # testar tb com 22 e 'Bóson' try: print("Valor:", item) divisao = 1/item print("1 dividido por", item, "é", divisao) except (TypeError): # Manipular tipo incorreto print("Você deve digitar apenas números!") print() except (ZeroDivisionError): # Manipular divisão por zero print("Não é possível dividir por zero.") print() except: # Manipular outras exceções não conhecidas print("Ocorreu a exceção", sys.exc_info()[0])
Valor: 0 Não é possível dividir por zero. Valor: 22 1 dividido por 22 é 0.045454545454545456 Valor: Bóson Você deve digitar apenas números!
A cláusula else
A cláusula else permite executar um bloco de código caso o código dentro do bloco try tenha sido executado sem erros (ou seja, sem lançar nenhuma exceção).
# Bloco else import sys item = 0 # testar tb com 22 e 'Bóson' try: print("Valor:", item) divisao = 1/item except (TypeError): # Manipular tipo incorreto print("Você deve digitar apenas números!") print() except (ZeroDivisionError): # Manipular divisão por zero print("Não é possível dividir por zero.") print() except: # Manipular outras exceções print("Ocorreu a exceção", sys.exc_info()[0]) else: print("1 dividido por", item, "é", divisao)
Valor: 0 Não é possível dividir por zero. Valor: 22 1 dividido por 22 é 0.045454545454545456
A cláusula finally
Todo código inserido em uma cláusula finally é executado independentemente de ter havido ou não erros na execução do bloco try.
Geralmente colocamos aqui código empregado para liberar recursos externos, como conexões a bancos de dados, acesso a recursos de rede ou um arquivo aberto.
# Bloco finally import sys item = 22 try: divisao = 1/item print("Valor:", item) except (TypeError): # Manipular tipo incorreto print("Você deve digitar apenas números!") print() except (ZeroDivisionError): # Manipular divisão por zero print("Não é possível dividir por zero.") print() except: # Manipular outras exceções print("Ocorreu a exceção", sys.exc_info()[0]) else: print("1 dividido por", item, "é", divisao) finally: print("O valor fornecido foi:", item)
Valor: 22 1 dividido por 22 é 0.045454545454545456 O valor fornecido foi: 22 Não é possível dividir por zero. O valor fornecido foi: 0 Você deve digitar apenas números! O valor fornecido foi: Fábio dos Reis
Lançar exceções manualmente
Podemos lançar exceções manualmente com a palavra-chave raise, que indica que uma exceção ocorreu. Quando uma declaração raise é executada, o Python cria um objeto da classe de exceção especificada.
# Declaração raise import sys item = -22 try: divisao = 1/item if item <= 0: raise ValueError("Não são aceitos números negativos nesta aplicação!") print("Valor:", item) except (TypeError): # Manipular tipo incorreto print("Você deve digitar apenas números!") print() except (ZeroDivisionError): # Manipular divisão por zero print("Não é possível dividir por zero.") print() except (ValueError) as erro: print(erro) except: # Manipular outras exceções print("Ocorreu a exceção", sys.exc_info()[0]) else: print("1 dividido por", item, "é", divisao) finally: print("O valor fornecido foi:", item)
Valor: 30 1 dividido por 30 é 0.03333333333333333 O valor fornecido foi: 30 Não são aceitos números negativos nesta aplicação! O valor fornecido foi: -22
Também podemos definir nossas próprias exceções, criando uma Exceção Definida pelo Usuário – assunto que abordaremos em outro artigo.
Escreva um comentário