inspect.ispackage: identifica paquetes Python

Publicado el: 05/10/2026
Tempo de leitura: 5 minutos
Código Python en pantalla que representa inspección de módulos y paquetes

inspect.ispackage es una función de introspección que permite comprobar si un objeto de módulo representa un paquete de Python. Esta diferencia resulta útil en generadores de documentación, sistemas de plugins, analizadores de código, herramientas para IDE y utilidades que recorren árboles de módulos.

En esta guía aprenderás qué considera Python un paquete, cómo utilizar inspect.ispackage, cómo mantener compatibilidad con versiones anteriores y qué errores conviene evitar al importar módulos, trabajar con paquetes de namespace o cargar extensiones.

Qué es un paquete de Python

Un paquete es un módulo que puede contener submódulos o subpaquetes. Los paquetes tradicionales suelen corresponder a directorios con un archivo __init__.py, pero los paquetes de namespace pueden abarcar varios directorios y no necesitan ese archivo. Después de la importación, el objeto del paquete expone metadatos como __spec__, __package__ y normalmente __path__.

Antes de disponer de una función específica, muchas herramientas comprobaban manualmente si existía __path__. Esa técnica funciona en numerosos casos, pero distribuye detalles internos del sistema de importación por todo el proyecto. Una función estándar expresa mejor la intención.

Uso básico

import inspect
import email
import math

print(inspect.ispackage(email))
print(inspect.ispackage(math))

La función devuelve verdadero para objetos que representan paquetes y falso para módulos normales, funciones, clases y otros valores. Recibe un objeto ya importado, no una cadena con el nombre del módulo.

Importar antes de clasificar

import importlib
import inspect


def es_nombre_de_paquete(nombre):
    modulo = importlib.import_module(nombre)
    return inspect.ispackage(modulo)

print(es_nombre_de_paquete("json"))
print(es_nombre_de_paquete("math"))

Importar un paquete puede ejecutar su código de inicialización. No aceptes nombres arbitrarios enviados por usuarios dentro de un proceso privilegiado. Los sistemas de plugins deben limitar los namespaces permitidos, aislar extensiones riesgosas y registrar los errores de importación.

Compatibilidad con versiones anteriores

Una biblioteca que todavía soporte versiones sin inspect.ispackage puede centralizar un fallback.

import inspect


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

Centralizar la compatibilidad facilita las pruebas y evita repetir condiciones de versión en distintos archivos.

Diferencia entre módulo y paquete

Todo paquete importado es un módulo, pero no todo módulo es un paquete. Por eso, inspect.ismodule no indica si el objeto puede contener hijos importables.

import inspect
import pathlib
import statistics

for objeto in (pathlib, statistics):
    print(objeto.__name__)
    print("módulo:", inspect.ismodule(objeto))
    print("paquete:", inspect.ispackage(objeto))

Esta clasificación permite decidir si una herramienta debe inspeccionar únicamente los miembros del módulo o continuar recorriendo una jerarquía.

Descubrir submódulos con pkgutil

import inspect
import pkgutil
import email

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

La verificación evita acceder a __path__ en un módulo común. Además, descubrir nombres no obliga a importar todos los hijos, lo que reduce efectos secundarios y tiempo de inicio.

Crear un registro de plugins

import importlib
import inspect
import pkgutil


def descubrir_plugins(nombre_raiz):
    raiz = importlib.import_module(nombre_raiz)
    if not inspect.ispackage(raiz):
        raise TypeError(f"{nombre_raiz!r} no es un paquete")

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

Conviene separar descubrimiento y activación. Primero identifica candidatos, después valida la configuración e importa solamente los plugins autorizados.

Generadores de documentación

Una herramienta de documentación puede usar inspect.ispackage para decidir si debe recorrer submódulos. Aun así, debe aplicar límites de profundidad, excluir módulos privados cuando corresponda y tolerar dependencias opcionales que no estén disponibles.

Importar toda una jerarquía puede abrir recursos, registrar manejadores o requerir bibliotecas nativas. Cuando el código no sea confiable, utiliza aislamiento.

Paquetes de namespace

Los paquetes de namespace pueden reunir partes del mismo espacio de nombres desde distintos directorios. Pueden no tener __init__.py. Por eso es mejor utilizar la semántica del sistema de importación que depender únicamente de la estructura física.

Al recorrer estos paquetes, elimina duplicados y conserva nombres totalmente cualificados.

Distribución instalada y paquete importado

inspect.ispackage clasifica un objeto que ya está en memoria. No verifica si una distribución está instalada, no obtiene su versión ni relaciona automáticamente el nombre importado con el nombre usado por el gestor de paquetes. Para eso utiliza importlib.metadata.

from importlib.metadata import version, PackageNotFoundError

try:
    print(version("requests"))
except PackageNotFoundError:
    print("distribución no instalada")

Una distribución puede proporcionar varios paquetes y su nombre puede ser distinto del nombre importado.

Manejo correcto de errores

import importlib
import inspect


def describir(nombre):
    try:
        modulo = importlib.import_module(nombre)
    except ModuleNotFoundError as error:
        if error.name == nombre:
            return {"nombre": nombre, "encontrado": False}
        return {"nombre": nombre, "encontrado": True, "dependencia": str(error)}
    except Exception as error:
        return {"nombre": nombre, "encontrado": True, "error": str(error)}

    return {
        "nombre": nombre,
        "encontrado": True,
        "paquete": inspect.ispackage(modulo),
    }

No informes todos los errores como si el módulo raíz no existiera. Una dependencia interna ausente es un problema diferente.

Seguridad

Que un objeto sea un paquete no significa que sea confiable. La importación puede ejecutar código arbitrario. Para extensiones utiliza listas permitidas, permisos mínimos, procesos separados, límites de recursos y aprobación administrativa.

Estrategia de pruebas

Incluye un módulo normal, un paquete tradicional y, si es relevante, un paquete de namespace. Prueba el fallback de compatibilidad de forma aislada. Para sistemas de plugins, crea estructuras temporales controladas y verifica que el orden de resultados sea determinista.

No dependas de paquetes externos instalados accidentalmente en la máquina de CI.

Rendimiento

La clasificación es barata. El coste real suele estar en importar y recorrer árboles grandes. Limita la recursión, omite namespaces pesados y separa una fase rápida de descubrimiento de otra fase opcional de análisis profundo.

Aplica caché solamente cuando las mediciones indiquen que es necesaria y define cómo invalidarla durante recargas en desarrollo.

Buenas prácticas

Utiliza nombres totalmente cualificados, ordena los resultados, centraliza la compatibilidad, separa descubrimiento de ejecución y conserva el contexto de los errores. No utilices la estructura del directorio como única fuente de verdad y no confundas clasificación con seguridad.

Contenidos relacionados

Consulta las guías de Academify sobre módulos y paquetes, importlib, entornos virtuales y publicación de paquetes. Revisa también la documentación oficial de inspect y la referencia del sistema de importación.

Conclusión

inspect.ispackage ofrece una forma clara y estándar de distinguir paquetes de módulos normales. Es útil en introspección, plugins, documentación y diagnóstico. Úsala sobre objetos importados, añade un fallback centralizado cuando sea necesario y mantén separadas la clasificación estructural, los metadatos de distribución y las decisiones de confianza.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Portátil con código y gráficos de rendimiento para analizar sys._jit en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    sys._jit: detecta y mide el JIT experimental

    Aprende sys._jit en Python para detectar soporte JIT experimental, medir rendimiento y evitar decisiones frágiles.

    Ler mais

    Tempo de leitura: 5 minutos
    05/10/2026
    Visualización de precisión numérica para cálculos con math.fma en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    math.fma: cálculo con un único redondeo

    Aprende math.fma en Python para multiplicar y sumar con un único redondeo y mejorar la estabilidad numérica.

    Ler mais

    Tempo de leitura: 7 minutos
    04/10/2026
    Programadora trabajando en automatización de unidades de Windows con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    os.listdrives: lista unidades de Windows en Python

    Aprende a listar unidades de Windows con os.listdrives y tratar rutas, discos extraíbles y errores con seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    04/10/2026
    Código binario que representa el protocolo Buffer en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    collections.abc.Buffer: tipa datos binarios

    Aprende collections.abc.Buffer en Python para tipar datos binarios, usar memoryview, reducir copias y manejar memoria con seguridad.

    Ler mais

    Tempo de leitura: 6 minutos
    03/10/2026
    Desarrollador configurando logs estructurados con LoggerAdapter merge_extra en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    LoggerAdapter merge_extra: contexto dinámico en logs

    Aprende LoggerAdapter merge_extra en Python para combinar contexto persistente y campos por llamada en logs estructurados seguros.

    Ler mais

    Tempo de leitura: 5 minutos
    03/10/2026
    Pantalla de portátil con código para análisis TLS usando ssl keylog_filename en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ssl keylog_filename: analiza TLS en Wireshark

    Aprende ssl keylog_filename en Python para inspeccionar sesiones TLS autorizadas en Wireshark sin desactivar el cifrado.

    Ler mais

    Tempo de leitura: 5 minutos
    02/10/2026