Como Verificar se uma Exceção é de um Tipo Específico em Python

PythonBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá como verificar se uma exceção é de um determinado tipo em Python, uma habilidade crucial para o tratamento eficaz de erros. O laboratório se concentra em entender a hierarquia de exceções e utilizar esse conhecimento para identificar tipos específicos de exceções.

O laboratório guia você pela exploração da hierarquia de exceções do Python, começando com a classe base BaseException e suas subclasses, como Exception. Você criará um script Python, exception_hierarchy.py, para imprimir a hierarquia de exceções, permitindo que você visualize as relações entre diferentes classes de exceção. Essa compreensão será então aplicada nas etapas subsequentes para verificar os tipos de exceção usando isinstance() e comparações diretas de classes.

Entenda a Hierarquia de Exceções

Nesta etapa, você aprenderá sobre a hierarquia de exceções em Python. Entender essa hierarquia é crucial para o tratamento eficaz de erros. As exceções em Python são organizadas em uma estrutura semelhante a uma árvore, com uma classe base no topo e classes de exceção mais específicas herdando dela.

A classe base para todas as exceções é BaseException. Herdando diretamente de BaseException estão Exception, GeneratorExit, KeyboardInterrupt e SystemExit. A classe Exception é a superclasse para a maioria das exceções embutidas que indicam erros que seu programa pode encontrar.

Vamos criar um script Python para explorar essa hierarquia.

  1. Abra seu editor VS Code.

  2. Crie um novo arquivo chamado exception_hierarchy.py no diretório ~/project.

    ~/project/exception_hierarchy.py
    
  3. Adicione o seguinte código ao arquivo exception_hierarchy.py:

    def print_exception_hierarchy(exception_class, indent=0):
        """Prints the exception hierarchy starting from a given exception class."""
        print('  ' * indent + str(exception_class))
        for subclass in exception_class.__subclasses__():
            print_exception_hierarchy(subclass, indent + 1)
    
    print("Exception Hierarchy:")
    print_exception_hierarchy(Exception)
    

    Este script define uma função recursiva print_exception_hierarchy que imprime a hierarquia de exceções começando pela classe Exception.

  4. Execute o script usando o seguinte comando no terminal:

    python exception_hierarchy.py
    

    Isso imprimirá uma estrutura semelhante a uma árvore da hierarquia de exceções no terminal.

    Exemplo de saída:

    Exception Hierarchy:
    <class 'Exception'>
      <class 'ArithmeticError'>
        <class 'FloatingPointError'>
        <class 'OverflowError'>
        <class 'ZeroDivisionError'>
          <class 'decimal.DivisionByZero'>
      <class 'AssertionError'>
      <class 'AttributeError'>
      <class 'BufferError'>
      <class 'EOFError'>
      <class 'ImportError'>
        <class 'ModuleNotFoundError'>
        <class 'ZipImportError'>
      <class 'LookupError'>
        <class 'IndexError'>
        <class 'KeyError'>
          <class 'tracemalloc.DomainKey'>
      <class 'MemoryError'>
      <class 'NameError'>
        <class 'UnboundLocalError'>
      <class 'OSError'>
        <class 'BlockingIOError'>
        <class 'ChildProcessError'>
        <class 'ConnectionError'>
          <class 'BrokenPipeError'>
          <class 'ConnectionAbortedError'>
          <class 'ConnectionRefusedError'>
          <class 'ConnectionResetError'>
        <class 'FileExistsError'>
        <class 'FileNotFoundError'>
        <class 'InterruptedError'>
          <class 'InterruptedSystemCall'>
        <class 'IsADirectoryError'>
        <class 'NotADirectoryError'>
        <class 'PermissionError'>
        <class 'ProcessLookupError'>
        <class 'TimeoutError'>
        <class 'UnsupportedOperation'>
        <class 'itertools.Incomplete'>
        <class 'signal.ItimerError'>
      <class 'ReferenceError'>
      <class 'RuntimeError'>
        <class 'NotImplementedError'>
          <class 'asyncio.exceptions.IncompleteReadError'>
          <class 'zlib.error'>
        <class '_frozen_importlib._DeadlockError'>
        <class 'RecursionError'>
      <class 'StopAsyncIteration'>
      <class 'StopIteration'>
      <class 'SyntaxError'>
        <class 'IndentationError'>
          <class 'TabError'>
      <class 'SystemError'>
      <class 'TypeError'>
      <class 'ValueError'>
        <class 'UnicodeError'>
          <class 'UnicodeDecodeError'>
          <class 'UnicodeEncodeError'>
          <class 'UnicodeTranslateError'>
      <class 'Warning'>
        <class 'BytesWarning'>
        <class 'DeprecationWarning'>
        <class 'EncodingWarning'>
        <class 'FutureWarning'>
        <class 'ImportWarning'>
        <class 'PendingDeprecationWarning'>
        <class 'ResourceWarning'>
        <class 'RuntimeWarning'>
        <class 'SyntaxWarning'>
        <class 'UnicodeWarning'>
        <class 'UserWarning'>
    

    Essa saída mostra a hierarquia de exceções, com Exception como a classe base e várias subclasses representando tipos específicos de erros. Entender essa hierarquia ajuda você a capturar exceções no nível apropriado de granularidade. Por exemplo, você pode capturar uma exceção específica como ZeroDivisionError ou uma exceção mais geral como ArithmeticError (que é pai de ZeroDivisionError).

Use isinstance() em Exceções

Nesta etapa, você aprenderá como usar a função isinstance() para verificar se uma exceção é uma instância de uma classe específica ou de uma tupla de classes. Isso é útil para lidar com diferentes tipos de exceções de forma flexível.

A função isinstance() recebe dois argumentos: um objeto e um classinfo. Ela retorna True se o objeto é uma instância do classinfo, ou de uma subclasse dele. Caso contrário, retorna False.

Vamos criar um script Python para demonstrar o uso de isinstance() com exceções.

  1. Abra seu editor VS Code.

  2. Crie um novo arquivo chamado isinstance_exception.py no diretório ~/project.

    ~/project/isinstance_exception.py
    
  3. Adicione o seguinte código ao arquivo isinstance_exception.py:

    try:
        result = 10 / 0
    except Exception as e:
        if isinstance(e, ZeroDivisionError):
            print("Caught a ZeroDivisionError!")
        elif isinstance(e, ArithmeticError):
            print("Caught an ArithmeticError!")
        else:
            print("Caught some other exception!")
    
    print("Program continues...")
    

    Neste script, estamos tentando dividir 10 por 0, o que levantará um ZeroDivisionError. Em seguida, capturamos a exceção e usamos isinstance() para verificar se ela é uma instância de ZeroDivisionError ou ArithmeticError.

  4. Execute o script usando o seguinte comando no terminal:

    python isinstance_exception.py
    

    Isso imprimirá "Caught a ZeroDivisionError!" no terminal.

    Exemplo de saída:

    Caught a ZeroDivisionError!
    Program continues...
    

    A saída mostra que a função isinstance() identificou corretamente a exceção como uma instância de ZeroDivisionError. Como ZeroDivisionError é uma subclasse de ArithmeticError, a primeira condição if é atendida e a mensagem correspondente é impressa.

    Agora, vamos modificar o script para capturar uma exceção mais geral.

  5. Modifique o arquivo isinstance_exception.py para o seguinte:

    try:
        result = int("abc")
    except Exception as e:
        if isinstance(e, ZeroDivisionError):
            print("Caught a ZeroDivisionError!")
        elif isinstance(e, ValueError):
            print("Caught a ValueError!")
        elif isinstance(e, ArithmeticError):
            print("Caught an ArithmeticError!")
        else:
            print("Caught some other exception!")
    
    print("Program continues...")
    

    Neste script modificado, estamos tentando converter a string "abc" em um inteiro, o que levantará um ValueError.

  6. Execute o script novamente usando o mesmo comando:

    python isinstance_exception.py
    

    Isso imprimirá "Caught a ValueError!" no terminal.

    Exemplo de saída:

    Caught a ValueError!
    Program continues...
    

    Essa saída mostra que isinstance() pode ser usado para diferenciar entre diferentes tipos de exceções e tratá-las de acordo.

Verificar com Classes de Exceção

Nesta etapa, você aprenderá como verificar classes de exceção específicas diretamente em seus blocos except. Esta é uma maneira mais direta e, muitas vezes, mais clara de lidar com exceções em comparação com o uso de isinstance().

Quando você usa except ExceptionType as e:, você está dizendo ao Python para capturar apenas exceções que são do tipo ExceptionType ou uma subclasse dele.

Vamos criar um script Python para demonstrar isso.

  1. Abra seu editor VS Code.

  2. Crie um novo arquivo chamado exception_classes.py no diretório ~/project.

    ~/project/exception_classes.py
    
  3. Adicione o seguinte código ao arquivo exception_classes.py:

    try:
        result = 10 / 0
    except ZeroDivisionError as e:
        print("Caught a ZeroDivisionError:", e)
    except ArithmeticError as e:
        print("Caught an ArithmeticError:", e)
    except Exception as e:
        print("Caught some other exception:", e)
    
    print("Program continues...")
    

    Neste script, estamos tentando dividir 10 por 0, o que levantará um ZeroDivisionError. Temos três blocos except: um para ZeroDivisionError, um para ArithmeticError e um para Exception.

  4. Execute o script usando o seguinte comando no terminal:

    python exception_classes.py
    

    Isso imprimirá "Caught a ZeroDivisionError: division by zero" no terminal.

    Exemplo de saída:

    Caught a ZeroDivisionError: division by zero
    Program continues...
    

    A saída mostra que o ZeroDivisionError foi capturado pelo primeiro bloco except.

    Agora, vamos modificar o script para levantar uma exceção diferente.

  5. Modifique o arquivo exception_classes.py para o seguinte:

    try:
        result = int("abc")
    except ZeroDivisionError as e:
        print("Caught a ZeroDivisionError:", e)
    except ValueError as e:
        print("Caught a ValueError:", e)
    except ArithmeticError as e:
        print("Caught an ArithmeticError:", e)
    except Exception as e:
        print("Caught some other exception:", e)
    
    print("Program continues...")
    

    Neste script modificado, estamos tentando converter a string "abc" em um inteiro, o que levantará um ValueError.

  6. Execute o script novamente usando o mesmo comando:

    python exception_classes.py
    

    Isso imprimirá "Caught a ValueError: invalid literal for int() with base 10: 'abc'" no terminal.

    Exemplo de saída:

    Caught a ValueError: invalid literal for int() with base 10: 'abc'
    Program continues...
    

    Essa saída mostra que o ValueError foi capturado pelo segundo bloco except.

    Ao especificar a classe de exceção diretamente no bloco except, você pode lidar com diferentes tipos de exceções de maneira clara e organizada. Essa abordagem é geralmente preferida em relação ao uso de isinstance() para o tratamento simples de exceções.

Resumo

Neste laboratório, você explorou a hierarquia de exceções em Python, que é crucial para o tratamento eficaz de erros. Você aprendeu que as exceções são organizadas em uma estrutura semelhante a uma árvore, com BaseException como a classe base e Exception como a superclasse para a maioria das exceções embutidas.

Você criou um script Python, exception_hierarchy.py, para imprimir a hierarquia de exceções, começando pela classe Exception. Ao executar o script, você observou a estrutura em árvore das exceções e seus relacionamentos, obtendo uma melhor compreensão de como as exceções são organizadas em Python.