Almacenamiento y serialización de datos con la biblioteca estándar de Python: json, pickle, csv

Para guardar datos en archivos o enviarlos por la red, se necesita serialización. Python ofrece tres herramientas estándar, cada una con un enfoque distinto: json, pickle, csv.

Formatos de entrega de datos

  • json: formato de texto legible para humanos, excelente para intercambio entre lenguajes.
  • pickle: formato binario que guarda objetos de Python tal cual, potente pero con riesgos de seguridad.
  • csv: formato de texto simple para datos tabulares, muy versátil.

En este artículo, presentaremos la elección de cada módulo según el tipo de datos y el destino.


1. JSON

1.1 Visión general

JSON (JavaScript Object Notation) es basado en texto y independiente de lenguaje. Se usa ampliamente en archivos de configuración, respuestas/solicitudes de API y logs. En Python se maneja con el módulo json.

1.2 API principal (lo más usado)

  • json.dump(obj, fp, ...) / json.load(fp, ...) : guardar/leer desde archivo.
  • json.dumps(obj, ...) / json.loads(s, ...) : convertir a/desde cadena.

Opciones útiles:

  • ensure_ascii=False – guarda caracteres internacionales sin escapar.
  • indent=2 – formato legible.
  • default=... – función para convertir tipos desconocidos.

1.3 Ejemplo básico

import json

data = {
    "name": "Alice",
    "age": 30,
    "skills": ["Python", "Data Science"]
}

with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

with open("data.json", "r", encoding="utf-8") as f:
    loaded = json.load(f)

print(loaded)

1.4 Solución sencilla a la limitación de tipos

JSON admite nativamente dict, list, str, int/float, bool, None. Para tipos como datetime, se puede usar default.

import json
from datetime import datetime, timezone

payload = {"created_at": datetime.now(timezone.utc)}

def to_jsonable(obj):
    if isinstance(obj, datetime):
        return obj.isoformat()
    raise TypeError(f"Not JSON serializable: {type(obj)!r}")

s = json.dumps(payload, default=to_jsonable, ensure_ascii=False)
print(s)

1.5 Ventajas y desventajas

Ventajas

  • Intercambio entre lenguajes.
  • Texto: depuración y control de versiones.
  • No ejecuta código al cargar.

Desventajas

  • Expresión limitada de tipos (datetime, set, Decimal, binario).
  • Con grandes volúmenes de datos, puede ser menos eficiente.

2. Pickle

2.1 Visión general

pickle serializa objetos de Python en binario. Al cargar, se recupera un objeto casi idéntico.

Es útil cuando:

  • Se desea conservar objetos complejos (clases, estructuras anidadas, modelos entrenados).
  • No se necesita interoperabilidad con otros lenguajes.

Evita usarlo cuando:

  • La fuente no es confiable (pickle.load() puede ejecutar código).
  • Se necesita compartir con sistemas no Python.

2.2 API principal (los 4 más usados)

  • pickle.dump(obj, file, protocol=...)
  • pickle.load(file)
  • pickle.dumps(obj, protocol=...)
  • pickle.loads(data)

Ejemplo típico de archivo:

import pickle

data = {"a": [1, 2, 3], "b": ("x", "y")}

with open("data.pkl", "wb") as f:
    pickle.dump(data, f)

with open("data.pkl", "rb") as f:
    loaded = pickle.load(f)

print(loaded)

2.3 ¿Qué es protocol y por qué es importante?

protocol define la versión del formato de pickle. El valor por defecto es el más adecuado para la versión actual de Python.

  • Si se necesita compatibilidad con versiones antiguas, se debe fijar un protocolo bajo.
  • Para optimizar tamaño y velocidad, se suele usar pickle.HIGHEST_PROTOCOL.
import pickle

with open("data.pkl", "wb") as f:
    pickle.dump({"x": 1}, f, protocol=pickle.HIGHEST_PROTOCOL)

2.4 Precaución importante

pickle.load() ejecuta el código embebido en el pickle. Por eso, nunca cargues un pickle de origen desconocido.

  • Si el objetivo es compartir, opta por json u otro formato de texto.

2.5 Ventajas y desventajas

Ventajas

  • Guarda prácticamente cualquier objeto de Python.
  • Generalmente más rápido que json para objetos complejos.

Desventajas

  • Riesgo de seguridad.
  • No interoperable con otros lenguajes.
  • Cambios en la definición de clases pueden inutilizar pickles antiguos.

3. CSV

3.1 Visión general

CSV (Comma-Separated Values) es el formato más sencillo para datos tabulares. Se usa en hojas de cálculo, exportaciones e importaciones de datos y logs simples.

3.2 API principal (lo más usado)

  • csv.reader, csv.writer – listas.
  • csv.DictReader, csv.DictWriter – diccionarios (más cómodo).

3.3 Ejemplo con DictWriter/DictReader

import csv

data = [
    {"name": "Alice", "age": 30, "city": "Seoul"},
    {"name": "Bob",   "age": 25, "city": "Busan"},
]

with open("people.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "age", "city"])
    writer.writeheader()
    writer.writerows(data)

with open("people.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    loaded = list(reader)

print(loaded)

3.4 Aspectos a tener en cuenta (3)

  1. Usar newline="" – evita saltos de línea dobles en Windows.
  2. Todos los valores son cadenas – conviene convertir tipos manualmente.
  3. Separadores y comillas dentro de los datos – el módulo csv maneja estos casos.

3.5 Ventajas y desventajas

Ventajas

  • Muy ligero y ampliamente soportado.
  • Ideal para datos tabulares simples.

Desventajas

  • No representa estructuras anidadas.
  • Falta de información de tipo.

4. Comparación y guía de selección

Característica JSON Pickle CSV
Compatibilidad Muy buena Solo Python Muy buena
Legibilidad Alta Baja (binario) Alta
Expresión de tipos Limitada Alta Limitada
Seguridad Relativamente segura Precaución necesaria Relativamente segura
Estructura Árbol (anidado) Objeto completo Tabla (fila/columna)

Resumen rápido

  • Intercambio entre sistemas → json.
  • Guardar objetos de Python íntegros → pickle (con precaución).
  • Exportar/leer datos tabulares → csv.

5. Guardar y cargar los mismos datos con los tres formatos

import json, pickle, csv

data = [
    {"id": 1, "name": "Alice", "score": 95.5},
    {"id": 2, "name": "Bob",   "score": 88.0},
]

# 1) JSON
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

with open("data.json", "r", encoding="utf-8") as f:
    json_loaded = json.load(f)

# 2) Pickle
with open("data.pkl", "wb") as f:
    pickle.dump(data, f)

with open("data.pkl", "rb") as f:
    pickle_loaded = pickle.load(f)

# 3) CSV
with open("data.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["id", "name", "score"])
    writer.writeheader()
    writer.writerows(data)

with open("data.csv", "r", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    csv_loaded = [
        {"id": int(row["id"]), "name": row["name"], "score": float(row["score"])}
        for row in reader
    ]

print(json_loaded)
print(pickle_loaded)
print(csv_loaded)
  • CSV requiere conversión de tipos al leer.
  • Pickle es cómodo pero exige cuidado con la fuente.

6. Conclusión

Con la biblioteca estándar de Python, la serialización y el almacenamiento de datos cubren una amplia gama de necesidades.

  • Si el objetivo es intercambio y legibilidad, elige json.
  • Si necesitas conservar objetos de Python tal cual, usa pickle (con precaución).
  • Si trabajas con datos tabulares simples, csv es la opción más ligera.

Selecciona el módulo que mejor se adapte a la forma y al propósito de tus datos, y obtendrás una solución rápida y limpia.