inspect.ispackage: identifique pacotes Python

Publicado em: 05/10/2026
Tempo de leitura: 5 minutos
Código Python em tela representando inspeção de módulos e pacotes

inspect.ispackage é uma função adicionada ao módulo inspect para verificar se um objeto de módulo representa um pacote Python. Embora pareça uma verificação simples, ela resolve um problema recorrente em ferramentas de introspecção, geradores de documentação, sistemas de plugins, analisadores de projetos e utilitários que percorrem módulos dinamicamente.

Neste guia, você vai entender o que caracteriza um pacote, como usar inspect.ispackage, como manter compatibilidade com versões anteriores, quais erros evitar e em quais cenários a função realmente melhora seu código.

O que é um pacote Python

Um pacote é um módulo capaz de conter outros módulos ou subpacotes. Tradicionalmente, ele é representado por um diretório com um arquivo __init__.py, embora pacotes de namespace também possam existir sem esse arquivo. Durante a importação, o Python registra metadados no objeto do módulo, como __spec__, __package__ e, em muitos casos, __path__.

Antes de inspect.ispackage, era comum verificar manualmente a presença de __path__. Essa técnica funciona em muitos casos, mas espalha detalhes de implementação pelo código e pode gerar decisões inconsistentes entre ferramentas.

Uso básico

import inspect
import pathlib
import json

print(inspect.ispackage(pathlib))
print(inspect.ispackage(json))

O resultado é verdadeiro quando o objeto representa um pacote e falso para módulos comuns, funções, classes e outros objetos. A função espera um objeto já importado. Ela não recebe diretamente uma string com o nome do pacote.

Importando antes de verificar

import importlib
import inspect


def verificar_nome(nome):
    modulo = importlib.import_module(nome)
    return inspect.ispackage(modulo)

print(verificar_nome("email"))
print(verificar_nome("math"))

Esse padrão é útil em ferramentas que recebem nomes configuráveis. Porém, importar código arbitrário pode executar efeitos colaterais definidos pelo pacote. Em sistemas de plugins, valide a origem, use ambientes controlados e não trate nomes fornecidos por usuários como automaticamente confiáveis.

Compatibilidade com versões anteriores

Bibliotecas que ainda suportam versões sem inspect.ispackage podem oferecer um fallback centralizado.

import inspect


def eh_pacote(objeto):
    funcao = getattr(inspect, "ispackage", None)
    if funcao is not None:
        return funcao(objeto)
    return inspect.ismodule(objeto) and hasattr(objeto, "__path__")

Esse fallback mantém a regra em um único lugar. Evite espalhar verificações de versão ou testes de atributos por todo o projeto.

Diferença entre módulo e pacote

Todo pacote importado é um módulo, mas nem todo módulo é um pacote. Portanto, inspect.ismodule(objeto) pode retornar verdadeiro para ambos. inspect.ispackage refina a classificação e responde se aquele módulo pode atuar como contêiner de submódulos.

import inspect
import math
import email

for objeto in (math, email):
    print(
        objeto.__name__,
        inspect.ismodule(objeto),
        inspect.ispackage(objeto),
    )

Explorando submódulos com pkgutil

Uma aplicação comum é percorrer apenas objetos que realmente são pacotes.

import inspect
import pkgutil
import email

if inspect.ispackage(email):
    for item in pkgutil.iter_modules(email.__path__):
        print(item.name, item.ispkg)

pkgutil.iter_modules trabalha com os caminhos do pacote. A checagem explícita torna a intenção clara e evita tentar acessar __path__ em um módulo comum.

Sistema de plugins

Em um sistema de plugins, você pode aceitar um pacote raiz e procurar módulos internos que sigam uma convenção.

import importlib
import inspect
import pkgutil


def descobrir_plugins(nome_pacote):
    raiz = importlib.import_module(nome_pacote)
    if not inspect.ispackage(raiz):
        raise TypeError(f"{nome_pacote} não é um pacote")

    encontrados = []
    for info in pkgutil.iter_modules(raiz.__path__, raiz.__name__ + "."):
        if info.name.endswith("_plugin"):
            encontrados.append(info.name)
    return encontrados

Descobrir nomes não exige necessariamente importar todos os submódulos. Isso reduz efeitos colaterais e melhora o tempo de inicialização.

Geradores de documentação

Ferramentas de documentação precisam decidir se devem listar somente membros do módulo ou também percorrer filhos. inspect.ispackage fornece uma condição semântica clara. Ainda assim, não importe indiscriminadamente toda a árvore: alguns módulos são opcionais, dependem do sistema operacional ou executam inicialização cara.

Pacotes de namespace

Pacotes de namespace permitem distribuir partes do mesmo namespace em diferentes diretórios. Eles podem não possuir __init__.py, mas continuam sendo pacotes do ponto de vista do sistema de importação. Uma API oficial é preferível a depender de uma regra baseada exclusivamente na estrutura física do diretório.

Não confunda pacote instalado com pacote importado

inspect.ispackage classifica um objeto em memória. Ela não verifica se uma distribuição está instalada no ambiente, não consulta metadados do gerenciador de pacotes e não confirma a versão instalada. Para isso, use importlib.metadata.

from importlib.metadata import version, PackageNotFoundError

try:
    print(version("requests"))
except PackageNotFoundError:
    print("distribuição não instalada")

O nome da distribuição também pode ser diferente do nome importado. Essa distinção evita muitos erros em ferramentas de diagnóstico.

Não use para validar segurança

Ser um pacote não significa que o código seja seguro, confiável ou autorizado. A função apenas classifica o objeto. Se sua aplicação carrega extensões, aplique listas permitidas, assinaturas, isolamento de processo e permissões mínimas.

Tratamento de erros

import importlib
import inspect


def descrever(nome):
    try:
        objeto = importlib.import_module(nome)
    except ModuleNotFoundError:
        return {"nome": nome, "encontrado": False}
    except Exception as erro:
        return {"nome": nome, "encontrado": True, "erro": str(erro)}

    return {
        "nome": nome,
        "encontrado": True,
        "pacote": inspect.ispackage(objeto),
    }

Não capture todos os erros e finja que o módulo não existe. Uma dependência ausente dentro do pacote, por exemplo, é diferente de o pacote raiz não ter sido encontrado.

Testes recomendados

Teste ao menos um módulo comum, um pacote tradicional e, quando seu projeto depender disso, um pacote de namespace. Teste também o fallback em uma função isolada. Evite alterar globalmente o módulo inspect durante testes concorrentes.

Desempenho

A classificação em si é barata. O custo relevante costuma estar na importação e na descoberta dos submódulos. Faça cache somente quando tiver evidência de necessidade e lembre que ambientes de desenvolvimento podem alterar módulos durante recargas.

Boas práticas

Centralize a compatibilidade, separe descoberta de importação, registre falhas com contexto e prefira nomes totalmente qualificados. Não dependa da ordem retornada pelo sistema de arquivos; ordene resultados quando a previsibilidade for importante.

Conteúdos relacionados

Veja também os conteúdos da Academify sobre módulos e pacotes, importlib, ambientes virtuais e publicação de pacotes. Consulte a documentação oficial de inspect e a referência do sistema de importação.

Conclusão

inspect.ispackage torna explícita uma classificação que antes dependia de verificações manuais. Ela é especialmente útil em introspecção, plugins, documentação e análise de módulos. Use-a sobre objetos importados, mantenha um fallback quando necessário e não confunda classificação estrutural com instalação, confiança ou segurança.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Notebook exibindo código e gráficos de desempenho para análise do sys._jit no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    sys._jit: detecte e meça o JIT experimental

    Aprenda sys._jit no Python para detectar suporte ao JIT experimental, medir desempenho e evitar decisões frágeis.

    Ler mais

    Tempo de leitura: 6 minutos
    05/10/2026
    Visualização de cálculos numéricos e precisão para math.fma no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    math.fma: cálculos com um único arredondamento

    Aprenda math.fma no Python para multiplicar e somar com um único arredondamento e melhorar cálculos numéricos.

    Ler mais

    Tempo de leitura: 6 minutos
    04/10/2026
    Desenvolvedores trabalhando em automação de unidades com Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    os.listdrives: liste unidades do Windows no Python

    Aprenda a listar unidades disponíveis no Windows com os.listdrives e tratar caminhos de forma segura no Python.

    Ler mais

    Tempo de leitura: 5 minutos
    04/10/2026
    Código binário representando o protocolo Buffer no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    collections.abc.Buffer: tipagem para dados binários

    Aprenda collections.abc.Buffer no Python para tipar dados binários, usar memoryview e evitar cópias desnecessárias com segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    03/10/2026
    Desenvolvedor configurando logs estruturados com LoggerAdapter merge_extra no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    LoggerAdapter merge_extra: logs com contexto dinâmico

    Aprenda LoggerAdapter merge_extra no Python para combinar contexto fixo e campos extras em logs estruturados com segurança.

    Ler mais

    Tempo de leitura: 4 minutos
    03/10/2026
    Tela de notebook com código para análise TLS usando ssl keylog_filename no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ssl keylog_filename: analise TLS no Wireshark

    Aprenda a usar ssl keylog_filename no Python para inspecionar conexões TLS no Wireshark com segurança e sem alterar o tráfego.

    Ler mais

    Tempo de leitura: 6 minutos
    02/10/2026