zipimport en Python: importa desde ZIP

Publicado el: 14/08/2026
Tempo de leitura: 5 minutos
Archivadores organizados que representan módulos importados directamente desde archivos ZIP con zipimport en Python

El módulo zipimport en Python permite que el sistema de imports cargue módulos y paquetes directamente desde archivos ZIP. La mayoría de las aplicaciones no necesita instanciarlo manualmente: cuando una ruta ZIP aparece en sys.path, Python selecciona automáticamente un zipimporter.

Esta capacidad sirve para distribuir colecciones de módulos en un solo archivo, cargar plugins empaquetados, reducir miles de archivos pequeños y comprender aplicaciones .pyz. Importar desde ZIP no vuelve seguro el código externo. El módulo se ejecuta en el proceso actual con los mismos privilegios de la aplicación.

Cómo funciona la importación desde ZIP

Una entrada de sys.path suele apuntar a un directorio, pero también puede nombrar un ZIP. El importador busca archivos .py y .pyc respetando la estructura de paquetes.

import sys

sys.path.insert(0, "plugins.zip")
import mi_plugin

print(mi_plugin.__file__)
# plugins.zip/mi_plugin.py

No necesitas escribir import zipimport en este caso. El mecanismo de imports elige el finder apropiado.

Estructura de paquetes

Los paquetes tradicionales conservan su estructura normal, incluyendo __init__.py cuando corresponda.

plugins.zip
├── mi_plugin/
│   ├── __init__.py
│   ├── comandos.py
│   └── validacion.py
└── utilidad.py

Después de añadir el ZIP, instrucciones como from mi_plugin import comandos siguen las reglas habituales.

Usa un subdirectorio interno como raíz

La entrada puede apuntar a una carpeta dentro del archivo:

sys.path.insert(0, "paquete.zip/lib")
import biblioteca

Solo lib/ se trata como raíz de imports. Esto ayuda cuando el ZIP contiene documentación, recursos y metadatos además del código.

Instancia zipimporter directamente

Herramientas de diagnóstico y loaders personalizados pueden crear zipimport.zipimporter.

from zipimport import zipimporter, ZipImportError

try:
    importador = zipimporter("plugins.zip")
except ZipImportError as error:
    print(f"Archivo inválido: {error}")
else:
    spec = importador.find_spec("mi_plugin")
    print(spec)

El constructor acepta el archivo completo o un prefijo interno como plugins.zip/lib. Una ruta inválida genera ZipImportError, también subclase de ImportError.

Prefiere find_spec

Los métodos antiguos fueron eliminados. Usa find_spec(), que devuelve un ModuleSpec compatible con importlib.

spec = importador.find_spec("mi_plugin.comandos")
if spec is None:
    raise ModuleNotFoundError("Plugin no encontrado")

modulo = __import__("mi_plugin.comandos", fromlist=["*"])

En código normal, una instrucción import sigue siendo más sencilla.

Lee fuente sin ejecutar

get_source() devuelve el texto fuente cuando está presente.

fuente = importador.get_source("mi_plugin")
if fuente is not None:
    print(fuente[:200])

Esto evita ejecutar el módulo, pero la fuente continúa siendo dato no confiable. Limita su tamaño y no la publiques sin autorización.

Para listar clases y funciones sin importar, consulta pyclbr en Python.

Obtén el objeto de código

get_code() devuelve el objeto de código del módulo.

objeto = importador.get_code("mi_plugin")
print(objeto.co_filename)

Ejecutarlo con exec() tiene los mismos riesgos que importar. No es un sandbox.

Lee datos auxiliares

get_data() devuelve bytes de una ruta dentro del archivo.

datos = importador.get_data(
    "plugins.zip/mi_plugin/config.json"
)

Para recursos de paquetes, importlib.resources ofrece una interfaz más estructurada. Consulta importlib.resources en Python.

Inspecciona nombre y tipo

get_filename() devuelve el valor que tendría __file__. is_package() informa si el nombre representa un paquete.

print(importador.get_filename("mi_plugin"))
print(importador.is_package("mi_plugin"))

Son útiles para navegadores, validadores de plugins y diagnósticos.

Limitación de extensiones nativas

El importador carga fuente y bytecode Python, pero no extensiones dinámicas .so o .pyd directamente. El loader del sistema operativo necesita binarios como archivos reales.

Instala las dependencias nativas o extrae binarios verificados a un directorio controlado. La guía de zipapp en Python explica la misma limitación.

Fuente frente a bytecode

Si el ZIP solo contiene .py, Python compila durante el import, pero no modifica el archivo para añadir .pyc. Nuevos procesos pueden repetir ese trabajo.

El bytecode incluido debe coincidir con el intérprete. El formato cambia entre versiones, por lo que la fuente suele ser más portable. Un .pyc no es cifrado.

Crea el ZIP

from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED

with ZipFile("plugins.zip", "w", ZIP_DEFLATED) as archivo:
    for ruta in Path("plugins").rglob("*.py"):
        archivo.write(ruta, ruta.relative_to("plugins"))

Excluye caches, artefactos, archivos de entorno, claves y credenciales. Normaliza las rutas y valida el resultado.

Sistemas de plugins empaquetados

Un servicio puede aceptar solo ZIPs firmados en un directorio aprobado, verificar hashes y cargar un entry point conocido. No debe ejecutar todos los módulos descubiertos.

from importlib import import_module

PERMITIDOS = {"informes", "exportacion"}

nombre = validar_nombre()
if nombre not in PERMITIDOS:
    raise PermissionError("Plugin no autorizado")

plugin = import_module(f"plugins.{nombre}")

Una allowlist reduce errores, pero no aísla código hostil. Ejecuta plugins de terceros en otro proceso o contenedor.

Colisiones y orden de sys.path

Insertar el ZIP en la posición cero puede sombrear módulos confiables con el mismo nombre. Un json.py empaquetado podría sustituir la biblioteca estándar esperada.

Usa namespaces propios, evita poner archivos no confiables primero y registra el origen. Consulta site en Python y pkgutil en Python.

Cache del importador

invalidate_caches() limpia el listado interno.

importador.invalidate_caches()

Si el archivo cambia durante la ejecución, invalida caches y evita reemplazos concurrentes. Es mejor publicar nombres versionados e inmutables y reiniciar workers.

Actualizaciones atómicas

No edites el ZIP en el lugar mientras otros procesos importan. Crea uno nuevo, verifica integridad y firma, sincroniza la escritura y reemplaza la ruta de forma atómica. Los módulos ya presentes en sys.modules siguen cargados.

ZIP64 y tamaño

Las versiones actuales soportan ZIP64, pero archivos enormes aumentan tiempo de apertura, memoria y riesgo de denegación de servicio. Define límites de tamaño y entradas.

Seguridad

  • Importar ejecuta código con privilegios del proceso.
  • Verifica editor, firma y hash.
  • Restringe rutas y nombres calificados.
  • No importes directamente uploads arbitrarios.
  • Evita sombrear módulos confiables.
  • Limita tamaño, entradas y profundidad.
  • Aísla plugins no confiables.
  • Registra versión y entry point.

Pruebas

Prueba paquetes, subpaquetes, archivos solo con fuente, solo con bytecode, prefijos internos, ZIP corrupto, comentarios, ZIP64 y colisiones. Verifica todas las versiones y plataformas objetivo.

Confirma que dependencias nativas fallen con un mensaje claro y que el sistema no use un módulo inesperado instalado en otra ruta.

Conclusión

zipimport en Python integra archivos ZIP con el mecanismo estándar de imports y permite cargar módulos sin extracción. Ofrece acceso a specs, fuente, objetos de código, datos, estado de paquete y nombres de archivo.

Úsalo con políticas claras de origen, rutas e aislamiento. Consulta la documentación oficial de zipimport y la PEP 273 sobre imports desde ZIP.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Desarrollador configurando un servidor HTTPS y certificado TLS con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crea un servidor HTTPS local en Python

    Aprende HTTPSServer en Python para crear servicios HTTPS locales, configurar certificados, usar hilos y comprender sus límites.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026
    Archivos protegidos que representan extracción segura de TAR con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extrae TAR con seguridad

    Aprende tarfile extraction_filter en Python para extraer archivos TAR con validación, seguridad y control de rutas.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026
    Código Python mostrando avisos controlados con catch_warnings
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    catch_warnings: captura warnings en pruebas Python

    Aprende catch_warnings en Python para capturar, probar y controlar avisos con filtros específicos y alcance seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código Python que representa referencias persistentes de pickle
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pickle persistent_id: serializa referencias externas

    Aprende pickle persistent_id en Python para referencias externas estables, validación, seguridad, rendimiento y compatibilidad.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código binario que representa buffers y vistas de memoria en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    memoryview.count: cuenta valores sin copiar buffers

    Aprende memoryview.count en Python para contar bytes y valores en buffers sin copias, con formatos, límites y buenas prácticas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python y anotaciones de tipos
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evita imports circulares en anotaciones

    Aprende annotationlib en Python para inspeccionar anotaciones diferidas, evitar imports circulares y crear herramientas seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026