← Volver al Blog

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 Team13 min de lecturaProgramación
B

Big JSON Team

Technical Writer

Expert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.

13 min lectura

# 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() y json.dump() para archivos
  • Siempre maneja errores con try/except
  • Usa ensure_ascii=False para caracteres Unicode
  • Para archivos grandes, considera streaming con ijson

¡Comienza a trabajar con JSON en Python hoy mismo!

Share:

Artículos Relacionados

Read in English