Python y JSON: Guía Completa del Módulo json
Aprende a trabajar con JSON en Python usando el módulo json. Incluye parsing, serialización, archivos JSON y mejores prácticas.
Big JSON Team
• Technical WriterExpert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.
# Python y JSON: Guía Completa del Módulo json
Python ofrece soporte excelente para trabajar con JSON a través de su módulo incorporado json. Esta guía completa te enseñará todo lo que necesitas saber.
El Módulo json de Python
El módulo json está incluido en la biblioteca estándar de Python, por lo que no requiere instalación adicional.
import json
# Listo para usar!
Funciones Principales
json.loads() - String a Python
Convierte una cadena JSON en un objeto Python:
import json
# Cadena JSON
json_string = '{"nombre": "Ana García", "edad": 30, "ciudad": "Madrid"}'
# Convertir a diccionario Python
datos = json.loads(json_string)
print(datos['nombre']) # "Ana García"
print(datos['edad']) # 30
print(type(datos)) # <class 'dict'>
json.dumps() - Python a String
Convierte un objeto Python en una cadena JSON:
import json
# Diccionario Python
persona = {
"nombre": "Carlos López",
"edad": 35,
"ciudad": "Barcelona",
"activo": True
}
# Convertir a JSON
json_string = json.dumps(persona)
print(json_string)
# {"nombre": "Carlos López", "edad": 35, "ciudad": "Barcelona", "activo": true}
json.load() - Archivo a Python
Lee JSON desde un archivo:
import json
# Leer archivo JSON
with open('datos.json', 'r', encoding='utf-8') as archivo:
datos = json.load(archivo)
print(datos)
json.dump() - Python a Archivo
Escribe JSON a un archivo:
import json
datos = {
"usuarios": [
{"nombre": "María", "edad": 28},
{"nombre": "Juan", "edad": 32}
]
}
# Escribir a archivo
with open('usuarios.json', 'w', encoding='utf-8') as archivo:
json.dump(datos, archivo, indent=2, ensure_ascii=False)
Mapeo de Tipos de Datos
Python a JSON
import json
datos_python = {
"diccionario": {"clave": "valor"}, # → object
"lista": [1, 2, 3], # → array
"cadena": "texto", # → string
"entero": 42, # → number
"flotante": 3.14, # → number
"booleano": True, # → true
"nulo": None # → null
}
json_string = json.dumps(datos_python)
print(json_string)
JSON a Python
| JSON | Python |
|------|--------|
| object | dict |
| array | list |
| string | str |
| number (int) | int |
| number (real) | float |
| true | True |
| false | False |
| null | None |
import json
json_string = '''
{
"objeto": {"a": 1},
"arreglo": [1, 2, 3],
"cadena": "texto",
"numero": 42,
"decimal": 3.14,
"booleano": true,
"nulo": null
}
'''
datos = json.loads(json_string)
print(type(datos["objeto"])) # <class 'dict'>
print(type(datos["arreglo"])) # <class 'list'>
print(type(datos["cadena"])) # <class 'str'>
print(type(datos["numero"])) # <class 'int'>
print(type(datos["decimal"])) # <class 'float'>
print(type(datos["booleano"])) # <class 'bool'>
print(type(datos["nulo"])) # <class 'NoneType'>
Formateo JSON en Python
Pretty Printing con indent
import json
datos = {
"nombre": "Laura Martínez",
"contacto": {
"email": "laura@ejemplo.com",
"telefono": "+34600123456"
},
"habilidades": ["Python", "Django", "PostgreSQL"]
}
# Sin formato (minificado)
print(json.dumps(datos))
# {"nombre":"Laura Martínez","contacto":{"email":"laura@ejemplo.com"...
# Con formato (pretty print)
print(json.dumps(datos, indent=2))
"""
{
"nombre": "Laura Martínez",
"contacto": {
"email": "laura@ejemplo.com",
"telefono": "+34600123456"
},
"habilidades": [
"Python",
"Django",
"PostgreSQL"
]
}
"""
Parámetro ensure_ascii
import json
datos = {
"nombre": "José García",
"ciudad": "Málaga",
"descripcion": "Programador especializado en Python"
}
# Con ensure_ascii=True (por defecto)
print(json.dumps(datos, ensure_ascii=True))
# {"nombre": "Jos\u00e9 Garc\u00eda", "ciudad": "M\u00e1laga"...
# Con ensure_ascii=False (preserva caracteres Unicode)
print(json.dumps(datos, ensure_ascii=False))
# {"nombre": "José García", "ciudad": "Málaga"...
Ordenar Claves
import json
datos = {
"z_ultima": "valor",
"a_primera": "valor",
"m_medio": "valor"
}
# Ordenar alfabéticamente
json_ordenado = json.dumps(datos, indent=2, sort_keys=True)
print(json_ordenado)
"""
{
"a_primera": "valor",
"m_medio": "valor",
"z_ultima": "valor"
}
"""
Separadores Personalizados
import json
datos = {"a": 1, "b": 2, "c": 3}
# Separadores compactos (para minificar)
print(json.dumps(datos, separators=(',', ':')))
# {"a":1,"b":2,"c":3}
# Separadores con espacios
print(json.dumps(datos, separators=(', ', ': ')))
# {"a": 1, "b": 2, "c": 3}
Trabajar con Archivos JSON
Leer Archivo JSON
import json
# Método básico
with open('config.json', 'r', encoding='utf-8') as f:
config = json.load(f)
print(config)
# Con manejo de errores
try:
with open('datos.json', 'r', encoding='utf-8') as f:
datos = json.load(f)
except FileNotFoundError:
print("Archivo no encontrado")
except json.JSONDecodeError as e:
print(f"Error de JSON: {e}")
Escribir Archivo JSON
import json
datos = {
"aplicacion": "MiApp",
"version": "1.0.0",
"configuracion": {
"puerto": 8000,
"debug": True
}
}
# Escribir con formato bonito
with open('config.json', 'w', encoding='utf-8') as f:
json.dump(datos, f, indent=2, ensure_ascii=False)
Actualizar Archivo JSON
import json
# Leer archivo existente
with open('usuarios.json', 'r', encoding='utf-8') as f:
usuarios = json.load(f)
# Añadir nuevo usuario
nuevo_usuario = {
"id": len(usuarios) + 1,
"nombre": "Roberto Sánchez",
"email": "roberto@ejemplo.com"
}
usuarios.append(nuevo_usuario)
# Guardar cambios
with open('usuarios.json', 'w', encoding='utf-8') as f:
json.dump(usuarios, f, indent=2, ensure_ascii=False)
Manejo de Tipos Personalizados
Serializar Objetos Personalizados
import json
from datetime import datetime
class Usuario:
def __init__(self, nombre, email, fecha_registro):
self.nombre = nombre
self.email = email
self.fecha_registro = fecha_registro
# Encoder personalizado
class EncoderPersonalizado(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Usuario):
return {
'nombre': obj.nombre,
'email': obj.email,
'fecha_registro': obj.fecha_registro.isoformat()
}
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
# Uso
usuario = Usuario("Ana", "ana@ejemplo.com", datetime.now())
json_string = json.dumps(usuario, cls=EncoderPersonalizado, indent=2)
print(json_string)
Deserializar a Objetos Personalizados
import json
from datetime import datetime
def decoder_usuario(dct):
if 'fecha_registro' in dct:
dct['fecha_registro'] = datetime.fromisoformat(dct['fecha_registro'])
return dct
json_string = '''
{
"nombre": "Carlos",
"email": "carlos@ejemplo.com",
"fecha_registro": "2024-01-15T10:30:00"
}
'''
datos = json.loads(json_string, object_hook=decoder_usuario)
print(type(datos['fecha_registro'])) # <class 'datetime.datetime'>
Trabajar con JSON Anidado
Acceder a Datos Anidados
import json
datos = {
"empresa": {
"nombre": "TechCorp",
"empleados": [
{
"id": 1,
"nombre": "María",
"departamento": {
"nombre": "Ingeniería",
"ubicacion": "Madrid"
}
},
{
"id": 2,
"nombre": "Pedro",
"departamento": {
"nombre": "Ventas",
"ubicacion": "Barcelona"
}
}
]
}
}
# Acceso seguro con get()
empresa = datos.get('empresa', {})
empleados = empresa.get('empleados', [])
for emp in empleados:
nombre = emp.get('nombre')
dept = emp.get('departamento', {}).get('nombre')
ubicacion = emp.get('departamento', {}).get('ubicacion')
print(f"{nombre} - {dept} ({ubicacion})")
Modificar Datos Anidados
import json
# Actualizar valores anidados
datos['empresa']['empleados'][0]['departamento']['ubicacion'] = 'Valencia'
# Añadir nuevo empleado
nuevo_empleado = {
"id": 3,
"nombre": "Laura",
"departamento": {
"nombre": "Marketing",
"ubicacion": "Sevilla"
}
}
datos['empresa']['empleados'].append(nuevo_empleado)
Validación y Manejo de Errores
Validar JSON
import json
def validar_json(json_string):
"""Validar si una cadena es JSON válido"""
try:
json.loads(json_string)
return True, "JSON válido"
except json.JSONDecodeError as e:
return False, f"Error en línea {e.lineno}, columna {e.colno}: {e.msg}"
# Probar
resultado, mensaje = validar_json('{"nombre": "Ana"}')
print(f"Válido: {resultado}, {mensaje}")
resultado, mensaje = validar_json('{nombre: "Ana"}') # Error: claves sin comillas
print(f"Válido: {resultado}, {mensaje}")
Manejo de Errores Común
import json
def cargar_json_seguro(nombre_archivo):
"""Cargar JSON con manejo completo de errores"""
try:
with open(nombre_archivo, 'r', encoding='utf-8') as f:
return json.load(f), None
except FileNotFoundError:
return None, "Archivo no encontrado"
except json.JSONDecodeError as e:
return None, f"JSON inválido: {e}"
except Exception as e:
return None, f"Error inesperado: {e}"
# Uso
datos, error = cargar_json_seguro('config.json')
if error:
print(f"Error: {error}")
else:
print("Datos cargados correctamente")
Trabajar con JSON Grande
Streaming con ijson
import ijson
# Para archivos JSON muy grandes
with open('archivo_grande.json', 'rb') as f:
# Parseo por streaming
objetos = ijson.items(f, 'usuarios.item')
for usuario in objetos:
print(usuario['nombre'])
# Procesar uno a la vez sin cargar todo en memoria
Lectura en Fragmentos
import json
def procesar_json_grande(nombre_archivo, tamaño_fragmento=1000):
"""Procesar JSON grande en fragmentos"""
with open(nombre_archivo, 'r', encoding='utf-8') as f:
datos = json.load(f)
# Procesar en fragmentos
if isinstance(datos, list):
for i in range(0, len(datos), tamaño_fragmento):
fragmento = datos[i:i + tamaño_fragmento]
# Procesar fragmento
yield fragmento
# Uso
for fragmento in procesar_json_grande('datos.json'):
print(f"Procesando {len(fragmento)} items")
Mejores Prácticas
1. Siempre Usa Encoding UTF-8
# ✅ Bueno
with open('datos.json', 'r', encoding='utf-8') as f:
datos = json.load(f)
# ❌ Malo (puede fallar con caracteres especiales)
with open('datos.json', 'r') as f:
datos = json.load(f)
2. Usa ensure_ascii=False para Caracteres No-ASCII
datos = {"ciudad": "Málaga", "país": "España"}
# ✅ Bueno (preserva caracteres)
json.dumps(datos, ensure_ascii=False)
# {"ciudad": "Málaga", "país": "España"}
# ❌ Malo (escapa caracteres)
json.dumps(datos)
# {"ciudad": "M\u00e1laga", "pa\u00eds": "Espa\u00f1a"}
3. Maneja Errores Apropiadamente
# ✅ Bueno
try:
datos = json.loads(json_string)
except json.JSONDecodeError as e:
print(f"Error de parseo: {e}")
# Manejar error apropiadamente
# ❌ Malo (sin manejo de errores)
datos = json.loads(json_string) # Puede crashear el programa
4. Valida Estructura de Datos
import json
def validar_estructura_usuario(datos):
"""Validar que los datos tienen la estructura esperada"""
campos_requeridos = ['nombre', 'email', 'edad']
if not isinstance(datos, dict):
return False, "Debe ser un diccionario"
for campo in campos_requeridos:
if campo not in datos:
return False, f"Falta campo requerido: {campo}"
return True, "Válido"
# Uso
datos = json.loads(json_string)
valido, mensaje = validar_estructura_usuario(datos)
Casos de Uso Prácticos
Archivo de Configuración
import json
import os
class ConfigManager:
def __init__(self, archivo_config='config.json'):
self.archivo = archivo_config
self.config = self.cargar()
def cargar(self):
"""Cargar configuración desde archivo"""
if os.path.exists(self.archivo):
with open(self.archivo, 'r', encoding='utf-8') as f:
return json.load(f)
return {}
def guardar(self):
"""Guardar configuración a archivo"""
with open(self.archivo, 'w', encoding='utf-8') as f:
json.dump(self.config, f, indent=2, ensure_ascii=False)
def get(self, clave, default=None):
"""Obtener valor de configuración"""
return self.config.get(clave, default)
def set(self, clave, valor):
"""Establecer valor de configuración"""
self.config[clave] = valor
self.guardar()
# Uso
config = ConfigManager()
config.set('tema', 'oscuro')
config.set('idioma', 'es')
print(config.get('tema')) # 'oscuro'
API Client
import json
import requests
class APIClient:
def __init__(self, base_url):
self.base_url = base_url
def get(self, endpoint):
"""Realizar petición GET"""
response = requests.get(f"{self.base_url}/{endpoint}")
return response.json()
def post(self, endpoint, data):
"""Realizar petición POST"""
response = requests.post(
f"{self.base_url}/{endpoint}",
json=data,
headers={'Content-Type': 'application/json'}
)
return response.json()
# Uso
api = APIClient('https://api.ejemplo.com')
usuarios = api.get('usuarios')
nuevo = api.post('usuarios', {'nombre': 'Ana', 'email': 'ana@ejemplo.com'})
Conclusión
Python ofrece soporte excelente para JSON a través del módulo json. Dominar estas técnicas te permitirá trabajar eficientemente con datos JSON en cualquier proyecto Python.
Puntos Clave
- Usa
json.loads()para parsear cadenas JSON - Usa
json.dumps()para convertir Python a JSON - Usa
json.load()yjson.dump()para archivos - Siempre maneja errores con try/except
- Usa
ensure_ascii=Falsepara caracteres Unicode - Para archivos grandes, considera streaming con ijson
¡Comienza a trabajar con JSON en Python hoy mismo!
Artículos Relacionados
JavaScript y JSON: Guía Completa de JSON.parse() y JSON.stringify()
Domina el trabajo con JSON en JavaScript. Aprende JSON.parse(), JSON.stringify() y mejores prácticas para aplicaciones web modernas.
Convertir JSON a Excel: Guía Completa con Python, JavaScript y Herramientas
Aprende a convertir JSON a Excel usando Python (pandas), JavaScript (xlsx), herramientas online y más. Incluye ejemplos prácticos y mejores prácticas.
JSON en Ciencia de Datos: Pandas, NumPy y Análisis de Datos
Aprende a usar JSON en ciencia de datos con Python. Incluye Pandas, NumPy, visualización y casos de uso prácticos.