shelve en Python: persistencia simple

Publicado el: 01/08/2026
Tempo de leitura: 5 minutos
Base de datos local que representa persistencia con shelve en Python

El módulo shelve permite guardar objetos Python en un archivo persistente con una interfaz parecida a un diccionario. Es útil cuando un script necesita conservar una pequeña cantidad de estado entre ejecuciones sin instalar un servidor de base de datos. Su sencillez no elimina los riesgos relacionados con seguridad, portabilidad, concurrencia y mantenimiento.

Cuándo conviene usar shelve

Utiliza shelve en scripts locales, prototipos, utilidades de línea de comandos, cachés pequeñas, automatizaciones personales y herramientas de escritorio. Puedes abrir una estantería, asignar valores a claves de texto y cerrarla. Para aplicaciones web, varios procesos, consultas complejas o datos críticos, es mejor elegir SQLite, PostgreSQL u otra base transaccional.

Ejemplo básico

import shelve

with shelve.open("datos_app") as db:
    db["usuario"] = {"nombre": "Ana", "nivel": 3}
    db["tema"] = "oscuro"

with shelve.open("datos_app") as db:
    print(db["usuario"])

El bloque with garantiza el cierre incluso si ocurre una excepción. Según el sistema operativo y la implementación dbm, una sola base lógica puede producir varios archivos con extensiones diferentes. Considera el nombre enviado a open como una base y no como la garantía de un único archivo.

Funcionamiento interno

shelve combina una base clave-valor de la familia dbm con la serialización de objetos mediante pickle. Las claves son cadenas. Los valores pueden ser listas, diccionarios, tuplas, instancias de clases y otros objetos serializables. Esta flexibilidad es cómoda, pero los datos no son legibles como JSON y nunca deben cargarse desde una fuente no confiable.

Actualización de valores mutables

Un error frecuente consiste en recuperar una lista o un diccionario, modificarlo y esperar que el cambio se guarde automáticamente. El patrón más seguro es volver a asignar el objeto modificado.

with shelve.open("datos_app") as db:
    perfil = db["usuario"]
    perfil["nivel"] += 1
    db["usuario"] = perfil

La opción writeback=True mantiene en caché los objetos consultados y los escribe al cerrar. Puede simplificar el código, pero aumenta el consumo de memoria y puede hacer que el cierre tarde mucho.

with shelve.open("datos_app", writeback=True) as db:
    db["usuario"]["nivel"] += 1

Usa writeback solamente con conjuntos pequeños y después de comprender su coste. La reasignación explícita suele ser más predecible.

Operaciones disponibles

Una estantería admite métodos conocidos como keys(), values(), items(), get() y pop(), además del operador in. Recorrer todos los valores puede ser costoso porque cada elemento necesita deserialización.

with shelve.open("datos_app") as db:
    db["contador"] = db.get("contador", 0) + 1
    if "configuracion" in db:
        print(db["configuracion"])
    for clave in db.keys():
        print(clave)

Modos de apertura

El argumento flag controla la apertura. El valor predeterminado c permite lectura y escritura y crea la base cuando no existe. r abre una base existente en modo de solo lectura. w abre una base existente para leer y escribir. n crea una base vacía y reemplaza la anterior.

Prefiere r en procesos que solo consultan información. Usa n únicamente para reconstrucciones deliberadas, pruebas aisladas o comandos de reinicio.

Reglas de seguridad

Nunca abras una estantería enviada por un usuario, descargada de internet, recibida por correo o modificada por una cuenta no confiable. Los datos pickle pueden ejecutar código durante la carga. Mantén los archivos en un directorio controlado, con permisos restrictivos y fuera de carpetas públicas.

shelve tampoco cifra los valores. Contraseñas, tokens, claves privadas y credenciales de API deben guardarse en un gestor de secretos o en otro sistema protegido.

Concurrencia e integridad

El módulo no ofrece un bloqueo portátil para varios escritores. Dos procesos escribiendo en la misma base pueden corromperla. La regla segura es permitir un solo escritor. Si varios procesos o máquinas necesitan compartir los datos, utiliza SQLite con transacciones o un servicio de base de datos diseñado para concurrencia.

Un cierre brusco o una pérdida de energía también puede dejar archivos inconsistentes. Realiza copias de seguridad, prueba la restauración y considera escribir cambios en una base temporal antes de sustituir la principal.

Portabilidad y migraciones

La implementación dbm cambia entre sistemas operativos e instalaciones. Los archivos creados en un equipo pueden no abrirse en otro. Los objetos pickle dependen además de rutas de módulos y definiciones de clases compatibles. Renombrar o mover una clase puede impedir la lectura de datos antiguos.

Para información que debe durar años, viajar entre plataformas o ser consumida por otros lenguajes, usa JSON, CSV, SQLite o un esquema documentado. shelve funciona mejor como persistencia local controlada.

Un repositorio sencillo

from pathlib import Path
import shelve

class Repositorio:
    def __init__(self, ruta: Path):
        self.ruta = str(ruta)

    def guardar(self, clave: str, valor) -> None:
        with shelve.open(self.ruta) as db:
            db[clave] = valor

    def obtener(self, clave: str, predeterminado=None):
        with shelve.open(self.ruta) as db:
            return db.get(clave, predeterminado)

    def eliminar(self, clave: str) -> bool:
        with shelve.open(self.ruta) as db:
            if clave not in db:
                return False
            del db[clave]
            return True

Encapsular el almacenamiento centraliza rutas, validación, registros y copias de seguridad. También facilita una futura migración a SQLite, porque el resto de la aplicación depende de tu interfaz y no de llamadas dispersas a shelve.

Pruebas seguras

En las pruebas, utiliza tempfile.TemporaryDirectory para obtener almacenamiento aislado y limpieza automática.

from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as carpeta:
    repo = Repositorio(Path(carpeta) / "prueba")
    repo.guardar("x", {"valor": 10})
    assert repo.obtener("x")["valor"] == 10

Buenas prácticas operativas

Usa claves estables y documentadas. Valida valores antes de escribir. Cierra siempre con with. Evita writeback para colecciones grandes. Mantén un único escritor. Añade copias de seguridad para datos valiosos. Incluye una exportación a JSON y comprueba que puede restaurarse en otra máquina.

Alternativas

JSON es mejor para datos simples y portables. SQLite aporta transacciones, consultas, índices y acceso concurrente más seguro. dbm guarda bytes y deja la serialización a la aplicación. SQLModel y SQLAlchemy son opciones cuando aumentan el dominio y las consultas.

Conclusión

shelve es un puente práctico entre un diccionario temporal y una base completa. Reduce código en proyectos locales pequeños, pero no debe convertirse en una dependencia crítica invisible. Úsalo solo con archivos confiables, comprende los riesgos de pickle, limita la concurrencia y planifica una migración cuando la durabilidad o la escala sean importantes.

Continúa con zipfile en Python, tempfile en Python, tomllib en Python y copy en Python. Consulta la documentación de shelve y la advertencia de seguridad de pickle.

Antes de adoptar el módulo, documenta qué datos se guardarán, durante cuánto tiempo y cómo se recuperarán ante un fallo. Esta decisión evita que un prototipo termine convertido en una dependencia de producción sin supervisión.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Terminal de comandos que representa parsing seguro con shlex en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    shlex en Python: comandos seguros

    Aprende shlex en Python para separar comandos, tratar comillas, usar quote y join y reducir riesgos de inyección de shell.

    Ler mais

    Tempo de leitura: 6 minutos
    02/08/2026
    Documentos de texto que representan comparación de versiones con difflib en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    difflib en Python: compara textos y archivos

    Aprende difflib en Python para comparar textos, medir similitud, crear diffs unificados, informes HTML y sugerencias de nombres.

    Ler mais

    Tempo de leitura: 6 minutos
    01/08/2026
    Panel de gráficos que representa análisis estadístico de datos en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    statistics en Python: análisis de datos

    Aprende statistics en Python para media, mediana, desviación, cuantiles, correlación, regresión, NormalDist y KDE.

    Ler mais

    Tempo de leitura: 7 minutos
    31/07/2026
    Gráficos de fracciones que representan números racionales exactos en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    fractions en Python: números racionales

    Aprende fractions en Python para aritmética racional exacta, reducción automática, limit_denominator, formato y conversiones seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    31/07/2026
    Calculadora y documentos que representan cálculos Decimal precisos en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    Decimal en Python: cálculos precisos

    Aprende Decimal en Python para cálculos exactos, dinero, quantize, redondeo, contextos y validación sin errores de float.

    Ler mais

    Tempo de leitura: 7 minutos
    30/07/2026
    Código digital que representa identificadores UUID únicos y ordenables en Python
    Bibliotecas y Módulos
    Foto de perfil de Leandro Hirt da Academify

    uuid en Python: IDs únicos y ordenables

    Aprende uuid en Python: versiones 4, 5, 6 y 7, validación, almacenamiento, IDs ordenables y buenas prácticas de seguridad.

    Ler mais

    Tempo de leitura: 7 minutos
    30/07/2026