🎓 Para PROS
Ya dominas lo básico. Ahora vamos a ver cosas que te harán entender Python de verdad y evitar bugs raros que vuelven loco a cualquiera.
Nivel: Esto es contenido avanzado. Si algo no lo pillas a la primera, no pasa nada.
Vuelve después de practicar más con lo básico.
📦 Mutables vs Inmutables
En Python, algunos objetos se pueden modificar después de crearlos y otros NO. Esto es súper importante y causa muchos bugs si no lo entiendes.
Inmutables (no se pueden cambiar)
int- números enterosfloat- números decimalesstr- strings/textostuple- tuplasbool- True/False
Mutables (sí se pueden cambiar)
list- listasdict- diccionariosset- conjuntos
¿Y esto qué significa en la práctica? Mira:
# Con INMUTABLES - el original NO cambia
texto = "hola"
texto_nuevo = texto.upper()
print(texto) # → "hola" (sigue igual)
print(texto_nuevo) # → "HOLA" (es una copia nueva)
# Con MUTABLES - ¡OJO! el original SÍ cambia
lista = [1, 2, 3]
lista.append(4)
print(lista) # → [1, 2, 3, 4] (la lista original cambió)
Bug clásico: Los strings NO se modifican "in place".
texto.upper() no cambia texto, devuelve una COPIA.
Si quieres guardar el cambio: texto = texto.upper()
🔗 El truco de las referencias
Cuando asignas una lista a otra variable, NO se copia. ¡Apuntan al mismo sitio!
# Esto NO es una copia
original = [1, 2, 3]
copia_falsa = original # ¡Apuntan al mismo sitio!
copia_falsa.append(4)
print(original) # → [1, 2, 3, 4] ¡¡TAMBIÉN CAMBIÓ!!
Es como si dos personas tuvieran la dirección de la misma casa. Si uno pinta la puerta, el otro también lo ve.
¿Cómo hacer una copia de verdad?
# Opción 1: slicing (la más común)
original = [1, 2, 3]
copia_real = original[:]
# Opción 2: list()
copia_real = list(original)
# Opción 3: .copy()
copia_real = original.copy()
# Ahora sí son independientes
copia_real.append(4)
print(original) # → [1, 2, 3] (no cambió)
print(copia_real) # → [1, 2, 3, 4]
🎯 Funciones: paso por valor vs referencia
Cuando pasas algo a una función, ¿puede la función modificar el original? Depende de si es mutable o inmutable.
Con inmutables: la función NO puede cambiar el original
def intentar_cambiar(numero):
numero = numero + 10
print(f"Dentro: {numero}")
x = 5
intentar_cambiar(x)
print(f"Fuera: {x}")
# Resultado:
# Dentro: 15
# Fuera: 5 ← ¡No cambió!
Con mutables: ¡SÍ puede cambiar el original!
def modificar_lista(lista):
lista.append(999)
print(f"Dentro: {lista}")
mi_lista = [1, 2, 3]
modificar_lista(mi_lista)
print(f"Fuera: {mi_lista}")
# Resultado:
# Dentro: [1, 2, 3, 999]
# Fuera: [1, 2, 3, 999] ← ¡SÍ cambió!
Regla fácil: Si no quieres que la función modifique tu lista original,
pásale una copia:
modificar_lista(mi_lista[:])
⚡ Trucos de competición
1. Operador ternario (if en una línea)
# En vez de esto:
if edad >= 18:
estado = "mayor"
else:
estado = "menor"
# Puedes hacer esto:
estado = "mayor" if edad >= 18 else "menor"
2. Desempaquetado múltiple
# Intercambiar dos variables sin variable temporal
a, b = b, a
# Desempaquetar listas
primero, *resto = [1, 2, 3, 4, 5]
print(primero) # → 1
print(resto) # → [2, 3, 4, 5]
# Primero y último
primero, *medio, ultimo = [1, 2, 3, 4, 5]
print(primero, ultimo) # → 1 5
3. Enumerate con índice
# En vez de esto:
i = 0
for item in lista:
print(i, item)
i += 1
# Haz esto:
for i, item in enumerate(lista):
print(i, item)
4. Zip para recorrer dos listas a la vez
nombres = ["Ana", "Luis", "Eva"]
notas = [8, 9, 7]
for nombre, nota in zip(nombres, notas):
print(f"{nombre}: {nota}")
# → Ana: 8
# → Luis: 9
# → Eva: 7
5. Any y All (muy útiles)
numeros = [2, 4, 6, 8]
# ¿Todos son pares?
print(all(n % 2 == 0 for n in numeros)) # → True
# ¿Alguno es mayor que 5?
print(any(n > 5 for n in numeros)) # → True
6. Counter para frecuencias (importar)
from collections import Counter
texto = "abracadabra"
frecuencias = Counter(texto)
print(frecuencias)
# → Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
# Las 2 más comunes
print(frecuencias.most_common(2))
# → [('a', 5), ('b', 2)]
7. Defaultdict para evitar KeyError
from collections import defaultdict
# Diccionario normal: da error si la clave no existe
normal = {}
# normal["nueva"] += 1 # ¡KeyError!
# Defaultdict: crea el valor por defecto automáticamente
conteo = defaultdict(int) # int() = 0
conteo["nueva"] += 1 # Funciona: crea 0 y suma 1
# Para listas
grupos = defaultdict(list)
grupos["A"].append("Ana") # Crea lista vacía y añade
🧪 Funciones lambda (funciones anónimas)
Son funciones pequeñas de una sola línea. Muy útiles para ordenar.
# Función normal
def doble(x):
return x * 2
# Lo mismo con lambda
doble = lambda x: x * 2
# Uso típico: ordenar con criterio personalizado
alumnos = [("Ana", 8), ("Luis", 9), ("Eva", 7)]
# Ordenar por nota (segundo elemento)
ordenados = sorted(alumnos, key=lambda x: x[1])
print(ordenados) # → [('Eva', 7), ('Ana', 8), ('Luis', 9)]
# Ordenar por nota descendente
ordenados = sorted(alumnos, key=lambda x: -x[1])
print(ordenados) # → [('Luis', 9), ('Ana', 8), ('Eva', 7)]
📐 Comprensiones avanzadas
List comprehension con condición
# Solo los pares
pares = [x for x in range(10) if x % 2 == 0]
# → [0, 2, 4, 6, 8]
# Con transformación y condición
dobles_pares = [x * 2 for x in range(10) if x % 2 == 0]
# → [0, 4, 8, 12, 16]
Dict comprehension
# Crear diccionario de cuadrados
cuadrados = {x: x**2 for x in range(1, 6)}
# → {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Invertir un diccionario
original = {"a": 1, "b": 2}
invertido = {v: k for k, v in original.items()}
# → {1: 'a', 2: 'b'}
🐛 Errores comunes que evitar
1. Modificar lista mientras la recorres
# ¡MAL! Comportamiento impredecible
for item in lista:
if condicion:
lista.remove(item)
# BIEN: crear lista nueva
lista = [item for item in lista if not condicion]
2. Lista como parámetro por defecto
# ¡MAL! La lista se comparte entre llamadas
def agregar(item, lista=[]):
lista.append(item)
return lista
# BIEN: usar None
def agregar(item, lista=None):
if lista is None:
lista = []
lista.append(item)
return lista
3. Comparar con == cuando debería ser "is"
# Para None, True, False usar "is"
if x is None: # ✓ Correcto
if x == None: # ✗ Funciona pero es feo
🏁 Resumen rápido
| Concepto | Qué recordar |
|---|---|
| Inmutables | int, float, str, tuple → no cambian, se crean copias |
| Mutables | list, dict, set → sí cambian, cuidado con referencias |
| Copiar lista | lista[:] o lista.copy() |
| Funciones | Mutables se modifican, inmutables no |
| Lambda | lambda x: x*2 = función en una línea |
| Counter | Cuenta frecuencias automáticamente |
Consejo final: No intentes memorizar todo esto. Practica, encuentra errores,
y vuelve aquí cuando algo no funcione como esperabas. Así es como se aprende de verdad.