Python esencial (avanzado)
Iteradores, generadores, excepciones, archivos, módulos
Por qué importa
Esta es la caja de herramientas del mundo real que vuelve productivo a Python a gran escala.
La idea
Los iterables te dejan transmitir datos de forma perezosa (lazy) (bueno para secuencias enormes / infinitas). Los generadores son la forma más barata de escribir un iterador. Las excepciones señalan los fallos sin dispersar comprobaciones de error. Los gestores de contexto (with) garantizan la limpieza.
Pruébalo
Generadores con yield: producen valores de forma perezosa:
def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
g = fib()
first_ten = [next(g) for _ in range(10)]
print(first_ten)
Expresiones generadoras frente a comprensiones de lista: la misma sintaxis, evaluación perezosa:
# Total memory: O(1) for the generator, O(n) for the list
nums = range(1_000_000)
total = sum(x * x for x in nums if x % 3 == 0)
print("sum of squares of multiples of 3:", total)
Excepciones + try/except/else/finally:
def safe_div(a, b):
try:
result = a / b
except ZeroDivisionError:
return None
except TypeError as e:
return f"type error: {e}"
else:
return result
finally:
# runs no matter what — log, close files, etc.
pass
print(safe_div(10, 2))
print(safe_div(10, 0))
print(safe_div(10, "x"))
Lo esencial de la biblioteca estándar
Rara vez necesitas escribir estructuras de datos desde cero: la biblioteca estándar tiene las versiones rápidas:
collections:deque,defaultdict,Counteritertools:accumulate,product,permutationsmath,statistics,random
Anotaciones de tipo + dataclasses
Las anotaciones de tipo documentan la intención (y potencian a los editores / verificadores de tipos); @dataclass escribe por ti el código repetitivo de __init__ / __repr__:
from dataclasses import dataclass
def add(a: int, b: int) -> int:
return a + b
@dataclass
class Point:
x: int
y: int
Verificación rápida
- P: ¿Por qué usar
with open(...)? R: Cierra el archivo automáticamente.
Mini ejercicios
- Escribe un generador que produzca números pares.
- Captura un
KeyErrorde forma segura. - Lee un archivo y cuenta sus líneas.
Buenas y malas prácticas
- Usa generadores para grandes flujos de datos.
- Captura excepciones específicas.
- No dejes archivos abiertos.
- No te tragues las excepciones en silencio.
Profundizando — iteración personalizada
Cualquier objeto que implemente __iter__ (devuelve el iterador) y __next__ (produce el siguiente valor o lanza StopIteration) funciona en un bucle for:
class CounterIter:
def __init__(self, n):
self.n = n
self.i = 0
def __iter__(self):
return self
def __next__(self):
if self.i >= self.n:
raise StopIteration
val = self.i
self.i += 1
return valErrores comunes
- Error: Usar
except:pelado en todas partes. Solución: Captura errores específicos. - Error: Olvidar el
yielden un generador. Solución: Usayieldpara transmitir valores. - Error: Leer archivos enormes con
read(). Solución: Itera línea por línea.
Conclusiones clave
- Los generadores (
yield) construyen iteradores con memoria constante. - Usa una expresión generadora
sum(x*x for x in nums)en lugar desum([x*x for x in nums])para entradas grandes. try/exceptpara el flujo de control ante fallos ESPERADOS; deja que los errores inesperados se propaguen.with open(path) as f:es el modismo correcto: elf.close()está garantizado.collections/itertoolste dan bloques de construcción rápidos y probados en batalla.