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:

  1. Erros de Sintaxe
  2. 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:

  1. Capturar uma exceção, que é detectar se uma exceção ocorreu; e
  2. 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.

Sobre Fábio dos Reis (1111 Artigos)
Fábio dos Reis trabalha com tecnologias variadas há mais de 25 anos, tendo atuado nos campos de Eletrônica, Telecomunicações, Programação de Computadores e Redes de Dados. É um entusiasta de Unix, Linux e Open Source em geral, adora Eletrônica e Música, e estuda idiomas, além de ministrar cursos e palestras sobre diversas tecnologias em São Paulo e outras cidades do Brasil.
Contato: Website

Escreva um comentário

Seu e-mail não será divulgado


*