Introducción
Las colecciones son el corazón de Python. Casi cualquier programa no trivial trabaja con grupos de datos: listas de usuarios, diccionarios de configuración, conjuntos de etiquetas. Conocerlos bien marca la diferencia entre código que funciona y código que es elegante y eficiente.
Python incluye cuatro colecciones principales en la librería estándar, cada una con características propias.
¿Qué vas a aprender en este lab?
- Listas: la colección más versátil
- Tuplas: secuencias inmutables
- Diccionarios: pares clave-valor
- Conjuntos: elementos únicos
- List, dict y set comprehensions
- Expresiones generadoras
Requisitos previos: fundamentos de Python (variables, bucles, funciones).
1. Listas
Una lista es una secuencia ordenada y mutable de elementos de cualquier tipo.
frutas = ["manzana", "naranja", "pera"]
mixta = [1, "hola", True, 3.14, None]
# Acceso por índice (empieza en 0, negativo desde el final)
print(frutas[0]) # manzana
print(frutas[-1]) # pera
# Slicing [inicio:fin:paso] — fin es exclusivo
print(frutas[0:2]) # ['manzana', 'naranja']
print(frutas[::-1]) # ['pera', 'naranja', 'manzana'] — invertida
Métodos principales
numeros = [3, 1, 4, 1, 5, 9, 2, 6]
numeros.append(7) # agrega al final: [3, 1, 4, 1, 5, 9, 2, 6, 7]
numeros.insert(0, 0) # inserta en posición: [0, 3, 1, ...]
numeros.remove(1) # elimina la primera ocurrencia de 1
ultimo = numeros.pop() # elimina y devuelve el último
primero = numeros.pop(0) # elimina y devuelve el índice 0
numeros.sort() # ordena en su lugar
numeros.sort(reverse=True) # ordena descendente
ordenados = sorted(numeros) # devuelve copia ordenada, no modifica original
print(numeros.count(1)) # cuántas veces aparece 1
print(numeros.index(5)) # índice de la primera ocurrencia de 5
numeros.reverse() # invierte en su lugar
copia = numeros.copy() # copia superficial
numeros.clear() # vacía la lista
Operaciones con listas
a = [1, 2, 3]
b = [4, 5, 6]
print(a + b) # [1, 2, 3, 4, 5, 6] — concatenación
print(a * 3) # [1, 2, 3, 1, 2, 3, 1, 2, 3] — repetición
print(3 in a) # True
print(len(a)) # 3
print(sum(a)) # 6
print(min(a), max(a)) # 1, 3
# Desempaquetado
x, y, z = a
print(x, y, z) # 1 2 3
primero, *resto = [1, 2, 3, 4, 5]
print(primero) # 1
print(resto) # [2, 3, 4, 5]
Ejercicio 1
Dada una lista de notas ([7.5, 8.0, 9.5, 6.0, 8.5, 7.0, 9.0]), calcula: la nota más alta, la más baja, el promedio, y devuelve una nueva lista solo con notas superiores al promedio, ordenadas de mayor a menor.
2. Tuplas
Una tupla es una secuencia ordenada e inmutable (no se puede modificar tras crearla). Son más rápidas que las listas y se usan para datos que no deben cambiar.
coordenadas = (40.7128, -74.0060) # latitud, longitud Nueva York
rgb = (255, 128, 0)
un_solo_elemento = (42,) # la coma es necesaria
# Acceso igual que listas
print(coordenadas[0]) # 40.7128
lat, lon = coordenadas # desempaquetado
# Las tuplas son inmutables
# coordenadas[0] = 0 # TypeError
Usos típicos
# Retorno múltiple de funciones
def min_max(lista):
return min(lista), max(lista) # devuelve tupla
minimo, maximo = min_max([3, 1, 4, 1, 5, 9])
print(f"Min: {minimo}, Max: {maximo}") # Min: 1, Max: 9
# Named tuples — como structs ligeros
from collections import namedtuple
Punto = namedtuple("Punto", ["x", "y"])
p = Punto(3, 4)
print(p.x, p.y) # 3 4
print(p) # Punto(x=3, y=4)
3. Diccionarios
Un diccionario almacena pares clave: valor. Las claves deben ser inmutables (strings, números, tuplas) y son únicas. Desde Python 3.7+ mantienen el orden de inserción.
persona = {
"nombre": "Julian",
"edad": 25,
"pais": "Colombia",
}
# Acceso
print(persona["nombre"]) # Julian
print(persona.get("email")) # None (sin excepción)
print(persona.get("email", "N/A")) # N/A
# Modificar / agregar
persona["email"] = "[email protected]"
persona["edad"] = 26
# Eliminar
del persona["pais"]
eliminado = persona.pop("edad") # elimina y devuelve
# Verificar
print("nombre" in persona) # True
print(len(persona)) # 2
Iterar diccionarios
notas = {"Matemáticas": 9.0, "Historia": 7.5, "Python": 10.0}
# Claves
for materia in notas:
print(materia)
# Valores
for nota in notas.values():
print(nota)
# Clave y valor
for materia, nota in notas.items():
print(f"{materia}: {nota}")
Métodos útiles
config = {"debug": False, "max_conexiones": 10}
defaults = {"debug": True, "timeout": 30, "max_conexiones": 5}
# update — combina, el segundo sobreescribe el primero
config.update(defaults)
print(config)
# {"debug": True, "max_conexiones": 5, "timeout": 30}
# Fusión de dicts (Python 3.9+)
resultado = config | {"puerto": 8080}
# setdefault — agrega solo si la clave no existe
config.setdefault("version", "1.0")
Contador de frecuencias
texto = "el gato y el perro y el pato"
palabras = texto.split()
conteo = {}
for palabra in palabras:
conteo[palabra] = conteo.get(palabra, 0) + 1
print(conteo)
# {'el': 3, 'gato': 1, 'y': 2, 'perro': 1, 'pato': 1}
# Con Counter de collections (más idiomático)
from collections import Counter
print(Counter(palabras))
Ejercicio 2
Dada una lista de productos [{"nombre": "Laptop", "precio": 1200, "categoria": "Electrónica"}, ...], escribe funciones para:
- Agrupar productos por categoría devolviendo un
dict[str, list] - Encontrar el producto más caro de cada categoría
- Calcular el precio total del inventario
4. Conjuntos (Sets)
Un conjunto es una colección de elementos únicos sin orden definido. Ideal para eliminar duplicados y operaciones matemáticas de conjuntos.
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
# Crear desde lista (elimina duplicados)
unico = set([1, 2, 2, 3, 3, 3])
print(unico) # {1, 2, 3}
# Operaciones
print(a | b) # {1,2,3,4,5,6} — unión
print(a & b) # {3,4} — intersección
print(a - b) # {1,2} — diferencia (en a pero no en b)
print(a ^ b) # {1,2,5,6} — diferencia simétrica
# Métodos
a.add(5)
a.discard(99) # elimina si existe, sin error si no existe
print(3 in a) # True — muy rápido (O(1))
Eliminar duplicados preservando orden
lista = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
sin_dup = list(dict.fromkeys(lista)) # preserva orden
print(sin_dup) # [3, 1, 4, 5, 9, 2, 6]
5. Comprehensions
Las comprehensions son la forma idiomática de crear colecciones a partir de otras, en una sola expresión.
List comprehension
# Forma larga
cuadrados = []
for x in range(1, 11):
cuadrados.append(x ** 2)
# List comprehension equivalente
cuadrados = [x ** 2 for x in range(1, 11)]
print(cuadrados) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# Con filtro
pares = [x for x in range(20) if x % 2 == 0]
print(pares) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# Transformar strings
palabras = ["hola", "mundo", "python"]
mayusculas = [p.upper() for p in palabras]
print(mayusculas) # ['HOLA', 'MUNDO', 'PYTHON']
# Anidada
matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
plana = [elem for fila in matriz for elem in fila]
print(plana) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Dict comprehension
nombres = ["Ana", "Bob", "Carlos"]
longitudes = {nombre: len(nombre) for nombre in nombres}
print(longitudes) # {'Ana': 3, 'Bob': 3, 'Carlos': 6}
# Invertir diccionario
original = {"a": 1, "b": 2, "c": 3}
invertido = {v: k for k, v in original.items()}
print(invertido) # {1: 'a', 2: 'b', 3: 'c'}
# Filtrar diccionario
precios = {"Laptop": 1200, "Mouse": 25, "Teclado": 80, "Monitor": 400}
caros = {k: v for k, v in precios.items() if v > 100}
print(caros) # {'Laptop': 1200, 'Monitor': 400}
Set comprehension
numeros = [1, 2, 2, 3, 4, 4, 5]
unicos_pares = {x for x in numeros if x % 2 == 0}
print(unicos_pares) # {2, 4}
Expresiones generadoras
Son como list comprehensions pero sin crear la lista en memoria — evalúan elemento a elemento. Ideales para grandes volúmenes de datos.
# List comprehension — crea TODA la lista en memoria
suma_lc = sum([x ** 2 for x in range(1_000_000)])
# Generadora — calcula uno a uno sin almacenar
suma_gen = sum(x ** 2 for x in range(1_000_000)) # nota: sin corchetes
# Mismo resultado, mucho menos memoria
print(suma_gen) # 333332833333500000
# Generador con función
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
gen = fibonacci()
primeros_10 = [next(gen) for _ in range(10)]
print(primeros_10) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Ejercicio 3
Dado el siguiente dataset de ventas:
ventas = [
{"producto": "Laptop", "precio": 1200, "unidades": 5},
{"producto": "Mouse", "precio": 25, "unidades": 50},
{"producto": "Teclado", "precio": 80, "unidades": 30},
{"producto": "Monitor", "precio": 400, "unidades": 10},
]
Usando comprehensions (sin bucles for explícitos):
- Lista de productos cuya facturación (
precio × unidades) supera 1000 - Diccionario
{producto: facturación} - Total facturado usando expresión generadora
6. Errores Comunes
Error 1 — Modificar una lista mientras la iteras
numeros = [1, 2, 3, 4, 5]
# Incorrecto: modifica la lista durante la iteración
for n in numeros:
if n % 2 == 0:
numeros.remove(n) # se saltan elementos
print(numeros) # [1, 3, 5] — parece correcto, pero con [1,2,3,4,5,6] falla
# Crea una nueva lista con comprehension
numeros = [n for n in numeros if n % 2 != 0]
Error 2 — Copia superficial de listas anidadas
original = [[1, 2], [3, 4]]
copia = original.copy() # copia superficial
copia[0].append(99)
print(original) # [[1, 2, 99], [3, 4]] — ¡la original también cambió!
# Copia profunda
import copy
copia = copy.deepcopy(original)
copia[0].append(99)
print(original) # [[1, 2], [3, 4]] — sin cambios
Error 3 — Usar lista cuando necesitas conjunto
# Verificar pertenencia en lista es O(n)
usuarios_vip = ["julian", "ana", "carlos"] # lista con 10.000 elementos → lento
if "julian" in usuarios_vip: # recorre hasta encontrar
print("VIP")
# Conjunto: O(1) sin importar el tamaño
usuarios_vip = {"julian", "ana", "carlos"}
if "julian" in usuarios_vip: # inmediato
print("VIP")
Resumen
| Colección | Mutable | Ordenada | Duplicados | Acceso por clave |
|---|---|---|---|---|
list |
Sí | Sí | Sí | Índice numérico |
tuple |
No | Sí | Sí | Índice numérico |
dict |
Sí | Sí (3.7+) | Claves únicas | Clave |
set |
Sí | No | No | — |
Próximos pasos
- POO en Python: clases, herencia, métodos especiales, dataclasses
- Módulos útiles:
itertools,functools,collections(Counter, defaultdict, deque) - Pandas: la librería de análisis de datos construida sobre estas colecciones