Serie Fundamentos de Python — Parte 3. Esta publicación continúa la Parte 1: Lo que Todo Principiante Debería Saber y la Parte 2: Variables y Tipos de Datos. Cada publicación de la serie toma un tema y lo explica a fondo. Esta trata sobre listas y diccionarios.
Si escribes Python por más de unos días, usarás listas y diccionarios todo el tiempo. Las páginas de un sitio web, los productos de una tienda en línea, las filas de la hoja de cálculo de un cliente, la respuesta de una API: casi cualquier dato real con el que trabajes termina en una lista, en un diccionario o en una combinación de ambos.
La Parte 2 presentó los dos tipos: cómo crearlos, leer un valor y hacer algunos cambios. Esta publicación va mucho más lejos. Aprenderás a agregar, quitar, buscar y ordenar elementos; a recorrerlos al estilo de Python; a construir listas y diccionarios nuevos en una sola línea con comprensiones; y a trabajar con datos anidados, las listas de diccionarios que casi siempre forman los datos del mundo real.
Como antes, abre el intérprete de Python (python3 en tu terminal) y prueba cada ejemplo mientras lees.
Repaso Rápido
Una lista es una colección ordenada y modificable de valores entre corchetes. Obtienes sus elementos por posición, empezando en 0:
pages = ["Home", "About", "Services", "Contact"]
print(pages[0]) # Home
Un diccionario guarda valores bajo claves entre llaves. Obtienes sus elementos por clave:
client = {"name": "Maria", "business": "Bright Bakery"}
print(client["name"]) # Maria
Una forma sencilla de elegir: usa una lista cuando importa el orden de los elementos y los vas a recorrer uno por uno; usa un diccionario cuando necesitas buscar cosas por nombre.
Listas a Fondo
Crear Listas
Puedes crear una lista con valores, o empezar con una vacía y llenarla después:
colors = ["#5B21B6", "#F59E0B", "#10B981"]
prices = [19.99, 49.00, 99.50]
tasks = [] # una lista vacía
print(len(colors)) # 3
print(len(tasks)) # 0
Una lista puede guardar cualquier tipo de valor, incluso una mezcla, pero en la práctica las listas suelen guardar elementos del mismo tipo. Así es mucho más fácil trabajar con ellas.
Acceder a Elementos y Rebanadas
Los índices empiezan en 0, y los índices negativos cuentan desde el final:
pages = ["Home", "About", "Services", "Portfolio", "Contact"]
print(pages[1]) # About
print(pages[-1]) # Contact
print(pages[-2]) # Portfolio
Pedir un índice que no existe produce un IndexError. Con cinco elementos, el último índice válido es 4:
pages[5] # IndexError: list index out of range
Para obtener varios elementos a la vez, usa una rebanada (slice): lista[inicio:fin]. La rebanada incluye inicio pero se detiene antes de fin:
print(pages[1:3]) # ['About', 'Services']
print(pages[:2]) # ['Home', 'About'] (desde el principio)
print(pages[2:]) # ['Services', 'Portfolio', 'Contact'] (hasta el final)
print(pages[-2:]) # ['Portfolio', 'Contact'] (los dos últimos)
Una rebanada también acepta un tercer número, el paso. Un paso de -1 avanza hacia atrás, lo que es una forma rápida de invertir una lista:
numbers = [1, 2, 3, 4, 5, 6]
print(numbers[::2]) # [1, 3, 5] (uno sí y uno no)
print(numbers[::-1]) # [6, 5, 4, 3, 2, 1]
Agregar Elementos
Hay tres formas principales de agregar elementos, y cada una hace algo un poco distinto:
pages = ["Home", "About"]
pages.append("Contact") # agrega un elemento al final
print(pages) # ['Home', 'About', 'Contact']
pages.insert(1, "Services") # agrega un elemento en una posición
print(pages) # ['Home', 'Services', 'About', 'Contact']
pages.extend(["Blog", "FAQ"]) # agrega cada elemento de otra lista
print(pages) # ['Home', 'Services', 'About', 'Contact', 'Blog', 'FAQ']
Ten cuidado con append() y las listas: append() agrega lo que le pasas como un solo elemento, así que agregar una lista con append() mete una lista dentro de tu lista. Usa extend() cuando quieras agregar los elementos uno por uno:
pages = ["Home"]
pages.append(["Blog", "FAQ"])
print(pages) # ['Home', ['Blog', 'FAQ']] ← probablemente no es lo que querías
También puedes unir dos listas en una lista nueva con +:
main_pages = ["Home", "About"]
extra_pages = ["Blog", "FAQ"]
all_pages = main_pages + extra_pages
print(all_pages) # ['Home', 'About', 'Blog', 'FAQ']
Quitar Elementos
De nuevo, hay varias opciones según lo que sepas del elemento:
pages = ["Home", "Services", "About", "Contact", "Blog", "FAQ"]
pages.remove("FAQ") # quita por valor (la primera coincidencia)
last = pages.pop() # quita el último elemento y lo devuelve
second = pages.pop(1) # quita el elemento del índice 1 y lo devuelve
del pages[0] # quita por índice, sin devolverlo
print(last) # Blog
print(second) # Services
print(pages) # ['About', 'Contact']
pop() es útil cuando quieres usar el elemento que quitaste; por ejemplo, para tomar la siguiente tarea de una lista de pendientes. Para vaciar una lista por completo, usa pages.clear().
remove() produce un ValueError si el valor no está en la lista, así que revisa primero con in cuando no estés seguro:
if "FAQ" in pages:
pages.remove("FAQ")
Buscar en una Lista
tags = ["python", "web", "seo", "python", "data"]
print("seo" in tags) # True (¿está en la lista?)
print("java" not in tags) # True
print(tags.index("seo")) # 2 (posición de la primera coincidencia)
print(tags.count("python")) # 2 (cuántas veces aparece)
Ordenar Listas
Python te da dos formas de ordenar, y la diferencia importa:
lista.sort()ordena la lista en su lugar: cambia la lista original y devuelveNone.sorted(lista)devuelve una lista nueva ordenada y deja la original sin cambios.
prices = [49, 19, 99, 5]
sorted_prices = sorted(prices)
print(sorted_prices) # [5, 19, 49, 99]
print(prices) # [49, 19, 99, 5] (sin cambios)
prices.sort()
print(prices) # [5, 19, 49, 99] (cambió en su lugar)
prices.sort(reverse=True)
print(prices) # [99, 49, 19, 5]
Ambas aceptan una key (clave): una función que Python aplica a cada elemento para decidir el orden. Por ejemplo, ordenar palabras por longitud, o alfabéticamente sin importar las mayúsculas:
services = ["SEO", "web design", "Hosting", "logo design"]
print(sorted(services)) # ['Hosting', 'SEO', 'logo design', 'web design']
print(sorted(services, key=str.lower)) # ['Hosting', 'logo design', 'SEO', 'web design']
print(sorted(services, key=len)) # ['SEO', 'Hosting', 'web design', 'logo design']
Fíjate en el primer resultado: de forma predeterminada, las mayúsculas van antes que las minúsculas. key=str.lower lo corrige.
Para invertir una lista sin ordenarla, usa lista.reverse() (en su lugar) o una rebanada [::-1] (lista nueva).
Recorrer una Lista
El ciclo más sencillo pasa por cada elemento:
pages = ["Home", "About", "Contact"]
for page in pages:
print(page)
Cuando también necesitas la posición de cada elemento, usa enumerate() en lugar de contar a mano. Con start=1, la cuenta empieza en 1, que es más natural para las personas:
for number, page in enumerate(pages, start=1):
print(f"{number}. {page}")
# 1. Home
# 2. About
# 3. Contact
Para recorrer dos listas en paralelo, usa zip():
pages = ["Home", "About", "Contact"]
visits = [1200, 340, 210]
for page, count in zip(pages, visits):
print(f"{page}: {count} visits")
Funciones Integradas Útiles
Estas funcionan con cualquier lista de números:
visits = [1200, 340, 210, 890]
print(len(visits)) # 4
print(sum(visits)) # 2640
print(min(visits)) # 210
print(max(visits)) # 1200
print(sum(visits) / len(visits)) # 660.0 (el promedio)
Comprensiones de Listas
Una comprensión de lista (list comprehension) construye una lista nueva a partir de otra en una sola línea. Es una de las funciones más queridas de Python. Compara estas dos formas de poner en mayúsculas el nombre de cada página:
pages = ["home", "about", "contact"]
# Con un ciclo normal
upper_pages = []
for page in pages:
upper_pages.append(page.upper())
# Con una comprensión de lista
upper_pages = [page.upper() for page in pages]
print(upper_pages) # ['HOME', 'ABOUT', 'CONTACT']
Léelo así: “dame page.upper() para cada page en pages”.
Agrega un if al final para filtrar elementos:
prices = [5, 19, 49, 99, 150]
affordable = [p for p in prices if p < 50]
print(affordable) # [5, 19, 49]
with_tax = [round(p * 1.0775, 2) for p in prices]
print(with_tax) # [5.39, 20.47, 52.8, 106.67, 161.62]
Las comprensiones son ideales para transformaciones y filtros cortos. Si una empieza a volverse larga o difícil de leer, un ciclo for normal es mejor opción.
Listas Anidadas
Una lista puede contener otras listas. Es una forma natural de guardar una tabla, donde cada lista interna es una fila:
schedule = [
["Mon", "Design mockups"],
["Tue", "Build homepage"],
["Wed", "Client review"],
]
print(schedule[1]) # ['Tue', 'Build homepage']
print(schedule[1][1]) # Build homepage
for day, task in schedule:
print(f"{day}: {task}")
schedule[1][1] se lee de izquierda a derecha: toma la fila 1 y luego el elemento 1 de esa fila.
Diccionarios a Fondo
Crear Diccionarios
client = {
"name": "Maria",
"business": "Bright Bakery",
"budget": 2500,
"is_active": True,
}
settings = {} # un diccionario vacío
Las claves suelen ser cadenas, pero pueden ser cualquier valor inmutable: los números y las tuplas también sirven. Una lista no puede ser clave, porque puede cambiar:
prices_by_size = {1: 9.99, 2: 17.99} # las claves numéricas funcionan
bad = {["a", "b"]: 1} # TypeError: unhashable type: 'list'
Cada clave solo puede aparecer una vez. Si asignas un valor a una clave que ya existe, el valor anterior se reemplaza.
Leer Valores de Forma Segura
Los corchetes producen un KeyError cuando la clave no existe. .get(), en cambio, devuelve None o el valor predeterminado que elijas:
print(client["name"]) # Maria
print(client.get("phone")) # None
print(client.get("phone", "N/A")) # N/A
Usa corchetes cuando la clave debe estar ahí (si falta, es un error real) y .get() cuando es opcional.
Para revisar si una clave existe, usa in. Ojo: in revisa las claves, no los valores:
print("budget" in client) # True
print("Maria" in client) # False ("Maria" es un valor, no una clave)
Agregar, Actualizar y Quitar
client["email"] = "[email protected]" # agrega una clave nueva
client["budget"] = 3000 # actualiza una clave existente
client.update({"budget": 3500, "phone": "555-0100"}) # actualiza varias a la vez
removed = client.pop("phone") # quita una clave y devuelve su valor
print(removed) # 555-0100
del client["is_active"] # quita una clave sin devolverla
print(client)
# {'name': 'Maria', 'business': 'Bright Bakery', 'budget': 3500, 'email': '[email protected]'}
Igual que .get(), .pop() acepta un valor predeterminado para no fallar cuando falta la clave: client.pop("fax", None).
Desde Python 3.7, los diccionarios recuerdan el orden en que se agregaron las claves, así que se imprimen y se recorren en ese orden.
Claves, Valores y Elementos
Tres métodos te dejan ver un diccionario desde distintos ángulos:
plan = {"Basic": 499, "Business": 1499, "Premium": 2999}
print(list(plan.keys())) # ['Basic', 'Business', 'Premium']
print(list(plan.values())) # [499, 1499, 2999]
print(list(plan.items())) # [('Basic', 499), ('Business', 1499), ('Premium', 2999)]
Recorrer un Diccionario
Recorrer un diccionario directamente te da sus claves. La mayoría de las veces querrás .items(), que te da cada clave junto con su valor:
for name, price in plan.items():
print(f"{name} plan: ${price:,}")
# Basic plan: $499
# Business plan: $1,499
# Premium plan: $2,999
También puedes usar .values() con las funciones integradas que viste antes:
print(sum(plan.values())) # 4997
print(max(plan.values())) # 2999
Contar con un Diccionario
Contar cuántas veces aparece algo es uno de los trabajos más comunes de un diccionario. El truco es .get(clave, 0), que empieza cada clave nueva en cero:
statuses = ["paid", "pending", "paid", "overdue", "paid", "pending"]
counts = {}
for status in statuses:
counts[status] = counts.get(status, 0) + 1
print(counts) # {'paid': 3, 'pending': 2, 'overdue': 1}
Consejo: la biblioteca estándar de Python tiene un atajo justo para esto:
from collections import Countery luegoCounter(statuses). Aun así, vale la pena conocer primero la versión manual: el mismo patrón sirve para totales, grupos y mucho más.
Ordenar un Diccionario por sus Valores
Los diccionarios no tienen un método .sort(), pero sorted() sí funciona con ellos. Para ordenar las claves según sus valores, pasa como key el propio método .get del diccionario:
visits = {"Home": 1200, "Contact": 210, "About": 340, "Blog": 890}
ranked = sorted(visits, key=visits.get, reverse=True)
print(ranked) # ['Home', 'Blog', 'About', 'Contact']
for page in ranked:
print(f"{page}: {visits[page]}")
Comprensiones de Diccionarios
Igual que las listas, los diccionarios tienen comprensiones. Usa llaves y un par clave: valor:
prices = {"Basic": 499, "Business": 1499, "Premium": 2999}
discounted = {name: round(price * 0.9) for name, price in prices.items()}
print(discounted) # {'Basic': 449, 'Business': 1349, 'Premium': 2699}
premium_only = {name: price for name, price in prices.items() if price > 1000}
print(premium_only) # {'Business': 1499, 'Premium': 2999}
Un uso común es construir un diccionario a partir de dos listas con zip():
pages = ["Home", "About", "Contact"]
visits = [1200, 340, 210]
page_visits = dict(zip(pages, visits))
print(page_visits) # {'Home': 1200, 'About': 340, 'Contact': 210}
Diccionarios Anidados
Los valores de un diccionario pueden ser otros diccionarios (o listas). Encadena las claves para llegar al dato que quieres:
site = {
"name": "Bright Bakery",
"contact": {"email": "[email protected]", "phone": "555-0100"},
"pages": ["Home", "Menu", "Contact"],
}
print(site["contact"]["email"]) # [email protected]
print(site["pages"][1]) # Menu
print(len(site["pages"])) # 3
Listas de Diccionarios: Trabajar con Datos Reales
Aquí es donde las listas y los diccionarios brillan juntos. Una lista de diccionarios es la forma más común de los datos reales: cada diccionario es un registro y la lista guarda todos los registros. Así se ven en Python las filas de una hoja de cálculo, los resultados de una base de datos y la mayoría de las respuestas de una API.
projects = [
{"client": "Bright Bakery", "type": "Website", "budget": 2500, "paid": True},
{"client": "Lopez Landscaping", "type": "SEO", "budget": 900, "paid": False},
{"client": "Calexico Coffee", "type": "Website", "budget": 3200, "paid": True},
{"client": "Valley Dental", "type": "Hosting", "budget": 300, "paid": False},
]
Con las herramientas de esta publicación, puedes responder preguntas reales sobre estos datos:
# ¿Cuántos proyectos hay?
print(len(projects)) # 4
# ¿Cuál es el valor total de todos los proyectos?
total = sum(p["budget"] for p in projects)
print(total) # 6900
# ¿Qué clientes no han pagado?
unpaid = [p["client"] for p in projects if not p["paid"]]
print(unpaid) # ['Lopez Landscaping', 'Valley Dental']
# Solo los proyectos de sitios web
websites = [p for p in projects if p["type"] == "Website"]
print(len(websites)) # 2
# El proyecto más grande
biggest = max(projects, key=lambda p: p["budget"])
print(biggest["client"]) # Calexico Coffee
# Todos los proyectos, del presupuesto más alto al más bajo
by_budget = sorted(projects, key=lambda p: p["budget"], reverse=True)
for p in by_budget:
print(f"{p['client']}: ${p['budget']:,}")
Los dos últimos ejemplos usan lambda, una forma corta de escribir una función diminuta en una sola línea. lambda p: p["budget"] simplemente significa “dado un proyecto p, usa su presupuesto”. Aprenderás bien las funciones en la Parte 6: Funciones; por ahora, piensa en ella como la forma de decirle a max() y sorted() qué valor comparar.
De JSON a Python y de Vuelta
Cuando recibes datos de una API o de un archivo .json, el módulo integrado json de Python los convierte en listas y diccionarios, las mismas estructuras con las que acabas de trabajar:
import json
response = '[{"page": "Home", "visits": 1200}, {"page": "Blog", "visits": 890}]'
data = json.loads(response) # texto JSON → lista de diccionarios de Python
print(data[0]["page"]) # Home
print(json.dumps(data[1])) # {"page": "Blog", "visits": 890} (Python → texto JSON)
Por eso las listas y los diccionarios son habilidades tan importantes: cuando te sientes cómodo con ellos, los datos de casi cualquier fuente son más de lo mismo. Para aprender a cargar datos desde archivos, APIs y bases de datos, consulta Python para Análisis de Datos: Cómo Acceder a tus Datos.
Todo Junto: Un Reporte Mensual de Proyectos
Este script combina todo lo de esta publicación en un reporte corto:
projects = [
{"client": "Bright Bakery", "type": "Website", "budget": 2500, "paid": True},
{"client": "Lopez Landscaping", "type": "SEO", "budget": 900, "paid": False},
{"client": "Calexico Coffee", "type": "Website", "budget": 3200, "paid": True},
{"client": "Valley Dental", "type": "Hosting", "budget": 300, "paid": False},
]
# Presupuesto total por tipo de proyecto
totals_by_type = {}
for project in projects:
kind = project["type"]
totals_by_type[kind] = totals_by_type.get(kind, 0) + project["budget"]
# Dinero recibido y dinero pendiente
received = sum(p["budget"] for p in projects if p["paid"])
owed = sum(p["budget"] for p in projects if not p["paid"])
unpaid_clients = sorted(p["client"] for p in projects if not p["paid"])
print("Revenue by type:")
for kind in sorted(totals_by_type, key=totals_by_type.get, reverse=True):
print(f" {kind}: ${totals_by_type[kind]:,}")
print(f"Received: ${received:,}")
print(f"Still owed: ${owed:,}")
print("Follow up with:")
for number, client in enumerate(unpaid_clients, start=1):
print(f" {number}. {client}")
Al ejecutarlo, imprime:
Revenue by type:
Website: $5,700
SEO: $900
Hosting: $300
Received: $5,700
Still owed: $1,200
Follow up with:
1. Lopez Landscaping
2. Valley Dental
Prueba a agregar otro proyecto a la lista y ejecútalo de nuevo: el reporte se actualiza solo.
Errores Comunes de Principiantes
Asignar el resultado de .sort(). .sort() cambia la lista y devuelve None, así que esto hace que pierdas tus datos:
prices = [49, 19, 99]
prices = prices.sort()
print(prices) # None
Llama a prices.sort() en su propia línea, o usa prices = sorted(prices).
Quitar elementos de una lista mientras la recorres. Python se salta elementos cuando la lista se encoge durante el ciclo:
tags = ["old", "old", "new", "old"]
for tag in tags:
if tag == "old":
tags.remove(tag)
print(tags) # ['new', 'old'] ← se saltó un "old"
Mejor crea una lista nueva con una comprensión: tags = [t for t in tags if t != "old"].
Usar append() cuando querías extend(). append() agrega una lista completa como un solo elemento. Usa extend() para agregar cada elemento.
Pasarse uno del final. Una lista de 5 elementos tiene índices del 0 al 4, así que items[5] produce un IndexError. Usa items[-1] para el último elemento.
Dar por hecho que una clave existe. client["phone"] produce un KeyError si la clave no está. Usa client.get("phone") para datos opcionales.
Esperar que in busque en los valores de un diccionario. "Maria" in client revisa las claves. Para buscar en los valores, usa "Maria" in client.values().
Copiar datos anidados con .copy(). .copy() hace una copia superficial: la lista o el diccionario exterior es nuevo, pero las listas y diccionarios de adentro siguen compartidos con el original. Para copiar por completo datos anidados, usa copy.deepcopy():
import copy
original = {"pages": ["Home", "About"]}
shallow = original.copy()
deep = copy.deepcopy(original)
original["pages"].append("Blog")
print(shallow["pages"]) # ['Home', 'About', 'Blog'] ← compartida con el original
print(deep["pages"]) # ['Home', 'About'] ← totalmente independiente
Ejercicios de Práctica
- Empieza con
pages = ["Home", "About"]. Agrega"Contact"al final, inserta"Services"en la posición 1 y luego quita"About". Imprime la lista final. - Con
scores = [88, 92, 79, 95, 61], imprime la calificación más alta, la más baja y el promedio redondeado a un decimal. - Usa una comprensión de lista para obtener solo los números pares de
range(1, 21). - Ordena
["banana", "Apple", "cherry"]alfabéticamente, sin importar las mayúsculas. - Cuenta cuántas veces aparece cada letra en la palabra
"mississippi"usando un diccionario. - Crea una lista de tres diccionarios que describan productos (nombre y precio). Imprime los nombres de los productos de menos de $50 y luego el nombre del producto más caro.
Para practicar más con datos reales, Limpieza de Datos con Python Pandas: De los Datos en Bruto al Análisis muestra lo que puedes hacer cuando tus datos ya no caben en listas y diccionarios simples.
Conclusión
Las listas y los diccionarios son las herramientas de trabajo de Python. Las listas mantienen los elementos en orden y te permiten agregarlos, quitarlos, ordenarlos y rebanarlos; los diccionarios te permiten guardar y buscar valores por nombre. Las comprensiones te dejan transformar ambos en una sola línea legible, y combinarlos, sobre todo como lista de diccionarios, te da una forma de representar casi cualquier dato del mundo real, desde las filas de una hoja de cálculo hasta las respuestas de una API.
La mejor forma de afianzar estas habilidades es usarlas con datos que te importen: las páginas de tu sitio web, una lista de clientes, tus gastos del mes. Empieza con una lista, luego un diccionario, luego una lista de diccionarios, y descubre cuántas preguntas puedes responder sobre tus propios datos.
Siguiente en la serie Fundamentos de Python: La Sentencia If, cómo hacer que tus programas decidan qué hacer.
Serie Fundamentos de Python: Parte 1: Lo que Todo Principiante Debería Saber · Parte 2: Variables y Tipos de Datos · Parte 3: Listas y Diccionarios · Parte 4: La Sentencia If · Parte 5: Entrada del Usuario y Ciclos While · Parte 6: Funciones · Parte 7: Clases · Parte 8: Archivos y Excepciones · Parte 9: Cómo Probar tu Código
